KMP模式匹配算法

来源:互联网 发布:淘宝买苹果手机可靠吗 编辑:程序博客网 时间:2024/06/05 08:57
思想:尽量利用已经部分匹配的结果信息,让i不要回溯,加快模式串的滑动速度。
例:
①如何由当前部分匹配结果确定模式向右滑动的新比较起点k?
② 模式应该向右滑多远才是高效率的?

一、next数组的求法

1.抓住匹配时的两个特征:

(1)设目前打算与T的第k字符开始比较 ,则T的1~k-1位=S的i-(k-1) ~i-1位(k是追求的新起点)
          


(2)刚才肯定是在S的i处和T的第j字符 处失配,则T的j-(k-1) ~j-1位= S的i-(k-1)~i-1位(1<k<j)
         
两式联立可得:‘T1…Tk-1’=‘Tj-(k-1) …Tj-1’,奇妙的结果: k 仅与模式串T有关!
2.新起点 k怎么求?
根据模式串T的规律:   ‘T1…Tk-1’=‘Tj-(k-1) …Tj-1’
由当前失配位置j(已知) ,可以归纳出计算新起点 k的表达式。

讨论:

(1)  next[ j ]的物理意义是什么?


next[j]函数代表模式T中最大相同前缀子串和后缀子串的长度加1。
可见,模式T中相似部分越多,next[j]的值越大。既表示模式T字符之间的相关度越高,也表示j位置以前与主串部分匹配的字符数越多。
即:next[j]越大,模式串向右滑动得越远,与主串进行比较的次数越少,时间复杂度就越低(时间效率)。
(2)  next[ j ]具体怎么求?—即KMP算法的实现
计算Next[j]的方法: 
当j=1时,Next[j]=0;   
//Next[j]=0表示根本不进行字符比较
当j>1时,Next[j]的值为:模式串的位置从1到j-1构成的串中所出现的首尾相同的子串的最大长度加1。
无首尾相同的子串时Next[j]的值为1。 
// Next[j]=1表示从模式串头部开始进行字符比较
 
j=1时, next[ j ]≡ 0;//属于“j=1”情况;
j=2时, next[ j ]≡ 1;// 找不到1<k<j的k,属于“其他情况”;
j=3时, k={2},只需查看‘T1’=‘T2’成立否,No则属于其他情况 
j=4时, k={2,3},要查看‘T1’=‘T3’ 及‘T1T2’=‘T2 T3’ 是否成立
j=5时, k={2,3,4},要查看‘T1’=‘T4’ ,‘T1T2’=‘T3T4’ 和 ‘T1T2T3’=‘T2T3T4’
以此类推,可得后续next[j]值。
代码实现:
void get_next(SString T, int  &next[ ] ){ //         //求模式串T的next函数值并存入数组next[ ]。i=1;  next[1]=0; j=0;while(i<strlen(T)){   if(j= = 0||T[i]= =T[j]){++i; ++j; next[i]=j;}else j=next[j]; }}// get_next
二、KMP算法的实现
Int Index_KMP(SString S, SString T, int pos) { //见教材P82   i=pos+1;      j=1;  while ( i<=strlen(S)&& j<=strlen(T) ) {      if (j==0|| S[i] = = T[j] ) {++i, ++j}   //不失配则继续比较后续字符    else {j=next[j];} //特点:S的i指针不回溯,而且从T的k位置开始匹配      }  if(j>T[0]) return i-T[0];  //子串结束,说明匹配成功  else return0;}
原创粉丝点击