一、算法的功能:
主字符串: ababcababababcab
模式串: abababab
判断在主串中是否存在模式串,如果存在,在哪个位置。
二、算法的思想:
设模式串为“P0...Pm-1",KMP匹配算法的思想是:当模式串中的字符Pj与主串中相应的字符Si不相等时,因其前j个字符(“P0...Pj-1”)已经获得了匹配,所以若模式串中的
“P0...Pk-1”与“Pj-k...Pj-1”相同,这时可令Pk与Si进行比较,从而使i无须回退。在KMP算法中,依据模式串的next函数值实现子串的滑动。若令next[j]=k,则next[j]表示当模式串
中的Pj与主串中相应字符不相等时,令模式串的Pk与主串的相应字符进行比较。
三、next数组
next函数的定义如下:
求next函数值的算法如下:
void get_next(char T[],int next[]){
int j = 1,k = 0;
next[1] = 0;
while(j<=T[0]){ //T[0]用于保存字符串的长度
if(k==0||T[j]==T[k]){
++j;++k;next[j]=k;
}
else
k=next[k];
}
}
手工求解next数组的方法:
(1)next[1]=0,next[2]=1(next[0]不使用)
(2)后面求解每一位的next[j]值时,根据j的前一位进行比较,令k=next[j-1];
(3)比较S[j-1]与S[k]进行比较:
a.如果相等,则该next[j]=k+1;
b.如果不相等,令k=next[k],若k不等于0,跳到(3);若k等于0,则next[j]=1。
例如模式串S=‘abaabcac’,依照以上算法求next数组:
(1)next[1]=0,next[2]=1
编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
S | a | b | a | a | b | c | a | c |
next | 0 | 1 |
(2)当j=3,此时k=next[j-1]=next[2]=1,比较S[2]与S[k](S[1])不等,此时k=next[k]=0,所以next[3]=1。
(3)当j=4,此时k=next[3]=1,比较S[3]与S[k](S[1])相等,所以next[4]=k+1=1+1=2。
(4)当j=5,此时k=next[4]=2,比较S[4]与S[k](S[2])不等,此时k=next[k]=next[2]=1,继续比较S[4]与S[k](S[1])相等,所以next[5]=S[k]+1=1+1=2。
(5)当j=6,此时k=next[5]=2,比较S[5]与S[k](S[2])相等,所以next[6]=k+1=2+1=3。
(6)当j=7,此时k=next[6]=3,比较S[6]与S[k](S[3])不等,此时k=next[k]=next[3]=1,继续比较S[6]与S[k](S[1])不等,此时k=next[k]=0,所以next[7]=1。
(7)当j=8,此时k=next[7]=1,比较S[7]与S[k](S[1])相等,所以next[8]=k+1=1+1=2。
最终求的next数组如下所示:
编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
S | a | b | a | a | b | c | a | c |
next | 0 | 1 | 1 | 2 | 2 | 3 | 1 | 2 |
四、进行主串和模式串的匹配
代码如下:
int KMP(char S[],char T[],int next[],int pos){
i=pos;
j=1;
while(i<=S[0]&&j<=T[0]){
if(j==0||S[i]==T[j]){
++i;
++j;
}
else
j=next[j];
}
}