kmp算法

来源:互联网 发布:e4a网络验证授权系统 编辑:程序博客网 时间:2024/06/04 20:11
 kmp算法思想 找到最长的滑动区间 
 
   在KMP算法的使用中,首要任务就是获取一个字符串的next数组
next数组可以用来求重复前缀,而且求出来的重复前缀是最小的
 
i 1 2 3 4 5 6 7 8       从第五个开始出现了不匹配
Aa b c ab c a c     按照朴素算法 每次比到B的最后一位发现不同又要重新从B的开头和A的下一个字符比较
Ba b c ac          朴素算法不可避免的存在“回溯”现象   效率低  
j 1 2 3 4 5           绿色部分在两个字符串中都是已知的  并且如果出现下图中的橙色部分
                    有一段字符相同  就不用一一比较了  直接滑动跳过不匹配的就好 
  
i  1 2 3 4 5 6 7 8    即B向右滑k个长度  使得后缀(A橙色部分)=前缀(B橙色部分) 
a b cab c a c      只有这样,我们才可以右移k位后从新的位置继续比较    
B  ab c a
j  1 2 3 4 5         
next 0  1  1  1  2                                          
 
//
1.移动位数 k = 已匹配的字符数 - 对应的部分匹配值(图中k=4-1=3)
 
2.字符串的部分匹配值 对应 完全匹配的字符串的最后一个字符的next值(上面 匹配了字符串abca 第二个a的next是1 则这个字符串的部分匹配值是2 而不是第二个a的部分匹配值)
 
3.部分匹配值是 完全前后缀中 最长的 共有元素 的长度
 
 
怎么确定滑动区间?
 
    建立一个数组 next,它跟B串一样长,next[j]表示B[j]与A[i]不匹配时 B应该滑到哪个位置
一旦不匹配时 查一下next的值 让A[i]与B[next[j]]继续比较
 
求next 数组 code:
 
<span style="font-family:SimSun;">void getnext(int len){int i=0,j=-1;next[i]=j;//起初next[0]=-1 一般任何串的第一个字符的模式值规定为-1。 while(i<len){if(j==-1||str[i]==str[j]){i++,j++;next[i]=j;}else j=next[j];}}/*例: A a b c a b c a cB a b c a c   位序i    0  1  2  3  4 模式串    a  b  c  a  cnxet(j) -1  0  0  0  1位序以0开始时 令next=-1  (位序以1开始时 令next=0) 第一次执行while 循环 j==-1  i++,j++后 i=1,j=0  next[1]=0,即b 的next 值为0;i=1 <len  str[i]==b,str[j]==str[0]==a,执行else 语句 j=next[j]=-1j==-1  执行if 语句  i=2,j=0; next[2]=0 依次执行直到i==len==5 终止循环 */ </span>
 
 

字符串匹配

 

       匹配的代码和求next数组的代码非常相似,匹配的过程和求next数组的过程其实是一样的。假设现在字符串B的前i个位置都和从某个位置开始的字符串A匹配,现在比较第i+1个位置。如果第i+1个位置相同,接着比较第i+2个位置;如果第i+1个位置不同,则出现不匹配,我们依旧要将长度为i的字符串分割,获得其最大公共长度next[i],然后从next[i]继续比较两个字符串。这个过程和求next数组一致,所以可以匹配代码如下

 

<span style="font-family:SimSun;">void kmp(){get_next();//调用next 数组 获得滑动区间 int i=0,j=0;while(i<strlen(buf))//buf 主串 str 标准串{if(j==-1||buf[i]==str[j]) i++,j++;else j=next[j];}}/*i      0  1  2  3  4  5  6  7buf    a  b  c  a  b  c  a  cstr    a  b  c  a  c next  -1  0  0  0  1j      0  1  2  3  4while循环 第一次  i=j=0,buf[0]=str[0]=a,i++,j++,i=1,j=1第二次  同上......第五次  i=4 j=4,buf[4]= b str[4]=c 两者不等 故j=next[4]= 1i      0  1  2  3  4  5  6  7buf    a  b  c  a  b  c  a  cstr             a  b  c  a  c next           -1  0  0  0  1j      0  1  2  3  4  5  6  7把str 右移 使上一次未匹配成功的buf[4]与str[next[4]]相比较 */</span>


 
详细了解next数据值的求解方法

位序       1   2   3   4   5   6   7   8
模式串     a   b   a   a   b   c   a   c
next值     0   1   1   2  2   3  1   2

next数组的求解方法是:
1.第一位的next值为0
2.第二位的next值为1
后面求解每一位的next值时,根据前一位进行比较
3.第三位的next值:第二位的模式串为b ,对应的next值为1;将第二位的模式串b与第一位的模式串a进行比较,不相等;则第三位的next值为1
4.第四位的next值:第三位的模式串为a ,对应的next值为1;将第三位的模式串a与第一位的模式串a进行比较,相同,则第四位的next值得为2
5.第五位的next值:第四位的模式串为a,对应的next值为2;将第四位的模式串a与第二位的模式串b进行比较,不相等;第二位的b对应的next值为1,则将第四位的模式串a与第一位的模式串a进行比较,相同,则第五位的next的值为2
6.第六位的next值:第五位的模式串为b,对应的next值为2;将第五位的模式串b与第二位的模式中b进行比较,相同,则第六位的next值为3
7.第七位的next值:第六位的模式串为c,对应的next值为3;将第六位的模式串c与第三位的模式串a进行比较,不相等;第三位的a对应的next值为1,则将第六位的模式串c与第一位的模式串a进行比较,不相同,则第七位的next值为1
8.第八位的next值:第七位的模式串为a,对应的next值为1;将第七位的模式串a与第一位的模式串a进行比较,相同,则第八位的next值为2
以上这种分析方法,位序是从1开始的,如果位序从0开始,刚第一位的next值为-1,后面的方法则相同
0 0
原创粉丝点击