`
jubincn
  • 浏览: 242601 次
  • 性别: Icon_minigender_1
  • 来自: 宁波
文章分类
社区版块
存档分类
最新评论

KMP算法深度解析

 
阅读更多

转自:http://blog.csdn.net/liuben/article/details/4409505


摘要:KMP算法是字符串匹配的经典算法,由于其O(m+n)的时间复杂度,至今仍被广泛应用。大道至简,KMP算法非常简洁,然而,其内部却蕴含着玄妙的理论,以至许多人知其然而不知其所以然。本文旨在解开KMP算法的内部玄妙所在,希望能够有助于学习与理解。

1、KMP算法
一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此称之为KMP算法。此算法可以在O(n+m)的时间数量级上完成串的模式匹配操作,其基本思想是:每当匹配过程中出现字符串比较不等时,不需回溯指针,而是利用已经得到的“部分匹配”结果将模式向右“滑动”尽可能远的一段距离,继续进行比较。

2、基于有限自动机理解算法
KMP 算法看似简单,其实要完全理解还是有困难的。KMP算法其实可以看成是一个有限自动机,分为 2 部分:第一部分自动机的构造 ( 对应一般的说法就是失效函数,转移函数, overlap 函数 ) ,第二部分在自动机上搜索过程。举个例子: 目标串 T = acabaabaabcacaabc; 模式串 P=abaabcac ;根据模式串构造自动机,向前的箭头表示搜索前进的方向。向后的箭头表示不匹配的回溯,即失效函数,或者状态变迁函数。例如:
f(j=1) = 0;
f(j=2) = 0;
f(j=3) = 1;
f(j=4) = 1;
f(j=5) = 2;
f(j=6) = 0;
f(j=7) = 1;

KMP本质上是构造了DFA并进行了模拟,因此很显然一旦从模版T构造了自动机D,用D去匹配主串S的过程就是线性的。KMP最引人入胜的地方就在于构造D的自匹配过程,它充分利用了D是一个DAG的性质,使得构造过程也是线性的。KMP算法不需要计算变迁函数,只用到辅助数组Next,即模式串自身的特征向量。特征向量可以用模式与其自身进行比较,预先计算出来,它可用于加快字符串匹配算法与有限自动机匹配器的执行速度。


3、Next特征数组构造
模式串P开头的任意个字符,把它称为前缀子串,如p0p1p2…pm-1。在P的第i位置的左边,取出k个字符,称为i位置的左子串,即pi-k+1... pi-2 pi-1 pi。求出最长的(最大的k)使得前缀子串与左子串相匹配称为,在第i位的最长前缀串。第i位的最长前缀串的长度k就是模板串P在位置i上的特征数n[i]特征数组成的向量称为该模式串的特征向量。
可以证明对于任意的模式串p=p0p1…pm-1,确实存在一个由模式串本身唯一确定的与目标串无关的数组next,计算方法为:
(1) 求p0…pi-1中最大相同的前缀和后缀的长度k;
(2) next[i] = k;

作为特殊情况,当i=0时,令next[i] = -1;显然,对于任意i(0≤i<m),有next[i] < i;假定已经计算得到next[i], 那么next[i+1] = ? 特征数ni ( -1≤ ni ≤ i )是递归定义的,定义如下:
(1) n[0] = -1,对于i > 0的n[i] ,假定已知前一位置的特征数 n[i-1]= k ;
(2) 如果pi = pk ,则n[i] = k+1 ;
(3) 当pi ≠ pk 且k≠0时,则令k = n [k -1] ; 让(3)循环直到条件不满足;
(4) 当qi ≠ qk 且k = 0时,则ni = 0;

根据以上分析,可以得到Next特征数组的计算方法,算法代码如下:

  1. voidget_next(SStringT,int&next[])
  2. {
  3. //求模式串T的next函数值并存入数组next
  4. i=1;next[1]=0;j=0;
  5. while(i<T[0])
  6. {
  7. if(j==0||T[i]==T[j])
  8. {
  9. ++i;++j;next[i]=j;
  10. }
  11. else
  12. {
  13. j=next[j];
  14. }
  15. }
  16. }

文献[5]中解释了以上计算方法存在一定缺陷,存在多比较的情况,可对其进行修正,得到如下算法:

  1. voidget_next(SStringT,int&next[])
  2. {
  3. //求模式串T的next函数值并存入数组next
  4. i=1;next[1]=0;j=0;
  5. while(i<T[0])
  6. {
  7. if(j==0||T[i]==T[j])
  8. {
  9. ++i;++j;
  10. if(T[i]!=T[j])
  11. next[i]=j;
  12. else
  13. next[i]=next[j];
  14. }
  15. else
  16. {
  17. j=next[j];
  18. }
  19. }
  20. }


4、算法实现
KMP算法的难点就是有限自动机的构造和特征向量的计算。解决了这两个问题后,具体匹配算法就很简单了。

int Index_KMP(SString S,SString T,int pos){
//利用模式串T的next函数求T在主串S中第pos个字符之后的位置的KMP算法。
//其中,T非空,1≤pos≤StrLength(S)。
i=pos; j=1;
while(i <= S[0] && j<= T[0]){
if(j == 0 || S[i] == T[j]) { ++i; ++j; }//继续比较后继字符
else j = next[j];//模式串象右移动
}
if(j>T[0]) return i-T[0];//匹配成功
else return 0;
}//Index_KMP


算法相关理论分析与证明,以及算法复杂性分析,若感兴趣请参考文献[3]、[4]、[5],这里不再赘述。

5、参考文献
[1]http://wansishuang.javaeye.com/blog/402018
[2]http://richardxx.yo2.cn/articles/kmp和extend-kmp算法.html
[3] KMP算法讲义PPT(Hu Junfeng, Peking University)
[4] 算法导论(第32章 字符串匹配)
[5] 数据结构(第4章 串)

分享到:
评论

相关推荐

    KMP算法深度解析:字符串匹配的高效之旅

    2. **搜索问题**:如二分查找、深度优先搜索(DFS)、广度优先搜索(BFS)等。 3. **图算法问题**:如最短路径问题、最小生成树问题等。 4. **动态规划问题**:解决具有重叠子问题和最优子结构特性的问题。 5. **...

    KMP算法精解

    KMP算法精解,由浅入深,层层递进,深度解析KMP算法的实现。

    Java 最新数据结构与算法全面深度解析完整视频

    本资源"Java 最新数据结构与算法全面深度解析完整视频"提供了一个全面的学习平台,帮助Java程序员提升在这两个关键领域的技能。 数据结构是组织和存储数据的方式,它允许我们以有效的方式访问和管理数据。在Java中...

    程序员面试算法设计解析

    8. **字符串处理**:KMP算法用于模式匹配,Rabin-Karp算法用于字符串搜索,Manacher's Algorithm用于找出字符串中的最长回文子串。 9. **位运算**:位运算在优化算法中起到关键作用,比如快速幂运算、判断奇偶性、...

    《数据结构》算法实现及解析

    6. **字符串处理**:字符串的基本操作,Trie树(字典树)和KMP算法用于模式匹配,以及Rabin-Karp和Boyer-Moore算法。 7. **动态规划**:基本概念,状态转移方程的构建,以及在背包问题、最长公共子序列、最短路径等...

    数据结构与算法经典问题解析-Java语言描述

    - **KMP算法**:处理模式匹配问题,避免了不必要的回溯。 - **Manacher's Algorithm**:解决在线查找字符串中最长回文子串的问题。 - **Rabin-Karp滚动哈希**:用于字符串查找,利用哈希减少比较次数。 6. **堆*...

    严蔚敏版数据结构算法实现与解析

    7. **字符串处理**:涉及到KMP算法、Rabin-Karp算法、Boyer-Moore算法等字符串匹配方法,以及动态规划在解决字符串问题中的应用。 8. **动态规划**:动态规划是一种求解最优化问题的有效方法,例如背包问题、最长...

    算法解析ACM

    此问题可以通过字符串匹配算法来解决,如KMP算法等。 **案例分析:Pku2406—Power Strings** 题目描述:定义一个幂字符串为某个非空字符串的重复序列。给定一个字符串,需要判断它是否为幂字符串。此问题同样可以...

    2018JAVA经典教程:数据结构与算法经典问题解析-Java语言描述

    - KMP算法、Boyer-Moore算法、Rabin-Karp算法:字符串匹配算法。 - Z函数、Manacher's Algorithm:线性时间复杂度的字符串模式匹配算法。 通过阅读《2018JAVA经典教程:数据结构与算法经典问题解析》,读者不仅...

    日常算法日常算法

    10. **字符串处理**:KMP算法、Rabin-Karp算法用于模式匹配,Z-Algorithm和Boyer-Moore算法用于文本搜索。这些算法在文本处理、搜索引擎等领域非常有用。 以上所述的算法都是程序员在日常工作中可能频繁接触到的。...

    数据结构算法实现及解析

    10. **字符串处理**:字符串在C语言中被视为字符数组,涉及到字符串的比较、查找、拼接等操作,如KMP算法用于模式匹配。 通过实际编写和解析这些算法,学习者可以深入理解数据结构的内在逻辑和算法的工作原理,为...

    50个经典C语言算法源码及解析说明.rar

    6. **字符串处理**:包括KMP算法、Rabin-Karp算法等,用于高效地匹配字符串。 7. **递归与分治策略**:如快速幂运算、汉诺塔问题、阶乘计算等,递归和分治是解决复杂问题的重要思路。 8. **堆数据结构**:包括最大...

    算法 第4版 高清中文版

    7. **字符串处理**:介绍了KMP算法、Rabin-Karp和Boyer-Moore字符串匹配算法,对于文本处理和搜索至关重要。 8. **随机化算法**:如Monte Carlo和Las Vegas算法,展示了如何在不确定性和概率中寻找解决方案。 9. *...

    算法竞赛之刘汝佳课件

    7. **字符串处理**:涉及KMP算法、Rabin-Karp滚动哈希、Z算法等字符串匹配方法,以及后缀自动机等高级技巧。 8. **数学基础**:如数论、组合数学、概率论等,这些都是解决一些算法问题的基础。 9. **编码技巧**:...

    算法概论配套之中文答案

    8. **字符串匹配**:如朴素算法、KMP算法、Boyer-Moore算法等,用于在文本中寻找子串出现的位置。 9. **排序算法的稳定性**:理解稳定排序和不稳定排序的区别,如冒泡排序是稳定的,而快速排序是不稳定的。 10. **...

    工作中常用算法(很实用)

    - **KMP算法**:避免了传统暴力匹配算法的重复比较,提高了字符串匹配的效率。 - **Boyer-Moore算法**:通过预处理模式串来减少字符比较次数,进一步提高了匹配速度。 #### 六、其他实用算法 除了上述算法之外,...

    labuladong的算法小抄.pdf

    2. 字符串匹配:如KMP算法,避免不必要的回溯,提高匹配效率。 3. 回溯法:在尝试所有可能的解决方案中,遇到无效或不符合条件的情况时退回一步,继续尝试其他可能性。 通过学习《labuladong的算法小抄》,读者可以...

    算法---源文件(主要是算法里提及到的源文件,很详细。)

    5. 字符串匹配:如KMP算法、Boyer-Moore算法,用于文本处理和信息检索。 三、源文件解析 1. 源代码结构:源文件通常包括函数定义、变量声明、控制流结构(if、for、while)、类定义等。 2. 注释:为了便于理解和...

    经典算法大全

    10. **字符串算法**:如KMP算法用于模式匹配,Rabin-Karp算法用于字符串搜索,以及Manacher's Algorithm解决最长回文子串问题。 通过阅读《经典算法大全》,读者不仅可以了解每种算法的基本原理,还能通过实例和...

    福建师大算法分析与设计的期末考试卷和答案

    4. 字符串匹配:暴力搜索、KMP算法、Boyer-Moore算法等。 四、答案解析的重要性 通过分析福建师大的这份期末考试卷和答案,我们可以: 1. 对照答案,检查自己对算法的理解是否正确,找出理解误区。 2. 学习解答...

Global site tag (gtag.js) - Google Analytics