关于KMP算法的一点个人理解

原创 2007年10月01日 05:37:00
 
KMP算法解析
前些日子,我因为面试需要,温习了下KMP算法,结果瞪着书看了3个小时愣是没有怎么看懂,不得已,不得不
求助于网络,在网络上搜索了半天,大概上是能理解,可是对于程序中getnext函数中有条语句k=next[k], 我怎么都没有找着是怎么来的,而且网络上的解答都没有说明为什么是这样的,没有办法,我自己做下来,好好研究了下,终于知道了是怎么回事。下面就是我对这个算法的一些理解没,如果有什么错误,希望大家能一起讨论。也可以给我发电子邮件或QQ联系:
E-MAIL:playing0816@163.com
QQ:574860234
KMP算法是对传统的字符串模式匹配算法的一个改进,传统的字符串匹配其时间复杂度是O(m*n),而KMP算法则是O(m+n)。
首先看下传统的字符串模式匹配函数
int PatternMathch(char * str1,char * pat)
{
       int i=0,j=0;
       while(i < strlen(str1) && j < strlen(pat))
       {
              if(str[i] == pat[j])
{
       i++;
       j++;
}
else
{
       i = i – j + 1;
       j = 0;
}
       }
       if(j == strlen(pat))
return i– j;
       return -1;
}
 
 
 
从上面的函数中我们可以知道,每当模式串和主串中的某个字符匹配不成功的时候,都需要将主串回溯到该次匹配的下个字符处,而模式串都需要回溯到第一个字符处。如下图所示
下标:0   1   2   3   4   5   6   7   8   9   10
主串:a   b   a   b   a   c   c   d    e   a   a
模式:a   b   a   c   
当第3个字符进行匹配的时候,发现主串[3] != 模式串[3],
这时候,传统的模式匹配算法需要进行回溯。回溯后的结果如下所示:
下标:0   1   2   3   4   5   6   7   8   9   10
主串:a   b   a   b   a   c   c   d    e   a   a
模式:    a   。。。。   
即用主串的第二个字符与模式的第一个字符进行匹配,这时候,主串从第一个匹配失败的地方(下标为3)回溯到下标为1的地方,而漠视串也从下标为3的地方回溯到下标为0的地方重新开始下次匹配。因此,才会导致该算法的匹配最坏情况下为O(m*n),当然在一般的情况下,模式串并不是每次都匹配到最后一个字符的时候才发现不匹配的。但是下面这种情况将导致传统的字符串模式匹配达到最坏的情况。
主串: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab
模式串:aaaab
在上面这种情况下,每次的匹配都是在模式串的最后一个字符进行匹配的时候,发现不匹配,然后每次都在这个时候才进行回溯。
 
其实,从我们对前面的模式匹配过程可以发现,当第一次匹配不成功时,主串并不需要回溯到该次匹配的下个位置重新开始匹配。因为模式串[0]=模式串[2],当模式串[3]!=主串[3]的时候,前面的字符串子川p[0]。。。p[2] == s[0]。。。s[1]。这已经是匹配成功的。
所以此时主串不需要回溯到下个位置开始重新匹配,而可以直接用模式串的[1] 去和主串的[3]进行比较,而进行匹配。
下标:0   1   2   3   4   5   6   7   8   9   10
主串:a   b   a   b   a   c   c   d    e   a   a
模式:        a   b。。。。   
 
现在我们的任务就是要对一个模式串,得到其当某个字符匹配失败的时候,主串不动,而模式串向进行右移后下个开始和主串进行匹配的字符的下标位置。
下面我们完成对这个数组的定义,
其中next[j]中的j表示当模式串中的第j个字符和主串不匹配的时候,下次匹配,模式串下个开始和主串当前位置的字符进行比较的位置(下标)。
next[]的定义:
next[j]=
=-1                                                当 j=0 时 
=max{k|1<k<j且'P(1)...P(k-1)'='P(j-k+1)...P(j-1)'}当此集合非空时
=0 其它情况
 
根据定义。我们可以得到下面的求next数组函数
//pat表示模式串,next表示数组,长度和pat的长度一样。
int getnext(char * pat,int * next)
{
    int j=0,k = -1;
    next[0] = -1;
    while(j < strlen(pat))
    {
        if(k == -1 || pat[k] == pat[j])
        {
            j++;
            k++;
            next[j] = k;
        }
        else
            k = next[k];
    }
}
 
算法解释:
根据定义,next[0] = -1.
而假设当前next[j]=k已经求得,则求next[j+1]??
由于next[j]=k,表示
p(0)p(1)…p(k-1)p(k)…p(j-k)p(j-k+1)…p(j-1)p(j)中有
红色部分的相等,即
p(0)p(1)…p(k-1) = p(j-k)p(j-k+1)…p(j-1)。
此时,如果有p(k)==p(j)
next[j+1]=next[j]+1;
如果p(k) != p(j)
则剩下的任务就是要在p(0)…p(k-1)中找到一个子串p(0)…p(m) == p(j-m)…p(j-1)
而且p(m) == p(j)
因为之前已经有p(0)p(1)…p(k-1) = p(j-k)p(j-k+1)…p(j-1)。
所以要求子串p(0)…p(m) == p(j-m)…p(j-1),只要在p(0)…p(k-1)中找这个子串就可以了(这步想法很重要)。
因为假设存在m,满足p(0)…p(m) == p(j-m)…p(j-1)
p(j-m)…p(j-1)一定与p(k-m)…p(k-1)相等的。
所以相当于p(0)…p(k-m)…p(k-1)串中求next[k],
假设next[k]=m(这个是已经求出来的了。),表示
p(0)p(1)…p(m-1) = p(k-m)…p(k-1)
这个时候除了满足这点之外,还需要满足p(m) == p(j)
只有这两个条件都满足的情况下,这个时候
next[j+1]才能等于m,
假设还是不能满足p(m) == p(j)这个条件。
又由上面的结果已经知道
p(0)p(1)…p(m-1) = p(k-m)…p(k-1)
这个是成立的。
即在p(0)…p(m-1)p(m)…p(k-1)已经有m了(因为next[k]=m),
p(0)p(1)…p(m-1) = p(k-m)…p(k-1)
那么现在再在p(0)…p(m-1)中找个子串p(0)…p(n-1)与p(k-n)…p(k-1)相等
假设找到了n,
p(0)…p(n-1) == p(k-n)…p(k-1)
那么由前面的next[j]=k
可以知道p(j-n)…p(j-1) == p(j-n)…p(j-1)
如果这个时候又p[n] = p[j]的话,则满足条件了,否则可以继续递归下去。
 

相关文章推荐

关于KMP算法中前缀函数(next函数)的一点个人理解

最近再刷笔试题的时候,发现了几道题需要求取字符串的next数组。 关于这部分知识,之前是有学过,代码也是比较简洁的,如下: public static int[] getNext(String ...

学习KMP算法的一点个人体会

这篇文章是对基于阶段性学习动态规划的一个实践性算法体会的记录,KMP算法,也就是大名鼎鼎的字符匹配算法,想必大家对这个字符匹配算法的目的已经很了解了,我最开始学习这个算法的时候其实也是主要是对算法中的...

【HDU1686】Oulipo 思路+解题报告+代码+KMP算法个人理解 【0.5%达成】

HDU的题意就是,给你一个字符串A,一个字符串B,求A在B中总共出现了几次,注意,重复的也算。 比如说 str1 = "ABA" str2 = "ABABABA" 这样的话,那么str1就在s...

KMP算法的个人理解

最近看了几天KMP算法...版本颇多... 总结起来其实就两类 一类求next,再求nextval 一类直接求nextval. 简单的,先说一些概念... 一般的搜索算法 BF.. ...

关于Kmp算法的一点小节

/* 函数功能:实现KMP算法 * */ #include using namespace std; int next[20]; void get_next(char *T,int ...
  • meiyuli
  • meiyuli
  • 2011年04月13日 09:55
  • 604

kmp算法一点合集

第一题 hdu 1711 Number Sequence题意:就是匹配看在不在。第二题 hdu 1686 oulipo点击打开hdu 1686思路:1 题目要求的是给定一个模式串个一个文本串,求出模式...
  • now_ing
  • now_ing
  • 2017年03月25日 09:36
  • 108

KMP算法:KMP算法个人理解+next数组细节处理的方法

一.KMP算法,是三位先辈的心血完成的一个匹配算法,堪称完美的算法。其中包含着很多有趣的细节。 (我们这里不啰嗦各种各样的理论,我们为的就是理解算法。) 所谓KMP算法,就是说现在给我们两个字符串,让...

KMP算法最浅显理解——一看就明白

说明KMP算法看懂了觉得特别简单,思路很简单,看不懂之前,查各种资料,看的稀里糊涂,即使网上最简单的解释,依然看的稀里糊涂。 我花了半天时间,争取用最短的篇幅大致搞明白这玩意到底是啥。 这里不扯概...

从DFA角度理解KMP算法

KMP 算法KMP(Knuth-Morris-Pratt)算法在字符串查找中是很高效的一种算法,假设文本字符串长度为n,模式字符串长度为m,则时间复杂度为O(m+n),最坏情况下能提供线性时间运行时间...

教你从头到尾彻底理解KMP算法

作者: July  、 saturnma     时间; 二零一一年一月一日-----------------------本文参考:数据结构(c语言版) 李云清等编著、算法导论作者声明:个人July ...
  • power721
  • power721
  • 2011年01月12日 19:14
  • 60589
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于KMP算法的一点个人理解
举报原因:
原因补充:

(最多只允许输入30个字)