一,KMP算法
KMP算法,全稱就是克努特-莫里斯-普拉特算法,是爲了避免大量的重複遍歷的情況。舉個例子:
圖 1 遍歷對比匹配圖1
圖2 遍歷對比匹配圖2
從圖1和圖2中可以看出來,在圖1中如果依次匹配,到5的時候匹配不成功,此時要回頭重新匹配,從i=2,j=1的位置開始匹配,這就是回溯法的思想,就這樣依次來回地回溯對比驗證,最後纔給出一個結論是否匹配成功。
圖 3 思路啓發一
思路啓發一,在圖3中可以看到在上面的匹配中,當i=j=5的時候,是S[5]與T[5]不相等,即不匹配,此時要重新進行匹配,分析可知S[1]=T[1],S[2]=T[2],S[3]=T[3],S[4]=T[4],而T[1]不等於T[2],T[1]不等於T[3],T[1]不等於T[4],T[2]也不等於T[3],T[2]也不等於T[4],此時就不用將T[1]與S[1]\S[2]\S[3]\S[4]相匹配,直接讓T[1]與S[5]進行匹配,即如圖3下面的演示那樣。這個時候提高了效率。
圖4 思路啓發二
這個思路啓發二看上去肯定不符合啓發一的情況,此時T[1]與S[2]是相等的,T[1]=T[2],這個時候可以直接認爲T[1]=S[2],匹配下一個,即匹配T[2]與S[3],依次匹配下去就會出現匹配成功的結果。
圖 5 思路啓發三
在圖5中可以看到,T[1]=T[2]=S[4]=S[5],此時可以直接從T[3]開始匹配,這樣就提高了效率。
圖6 思路啓發四
在圖6思路啓發四中可以看到,根據前面的一二三的經驗這個時候可以很明顯從T[4]開始匹配。這樣得出的一些規律就是KMP算法。問題是由模式串決定的,而不是目標串決定的。主要是爲了保證 i 不再回溯。避免了效率低下的問題。
二,KMP算法的實現
1,首先get_next函數的編寫
#include <stdio.h>
typedef char* String;
void get_next(String T,int *next)
{
int i = 1;
int j = 0;
next[1] = 0;
while(i < T[0])
{
if(0 == j || T[i] == T[j])
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j];
}
}
}
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main()
{
char str[255] = "ababaaaba";
int next[255];
int i = 1;
str[0] = 9;
get_next(str, next);
for(i=1;i<10;i++)
{
printf("%d ",next[i]);
}
return 0;
}
結果爲
獲取next數組的結果圖
2,KMP算法的實現
//返回子串T在主串S第pos個字符之後的位置
int Index_KMP(String S,String T,int pos)
{
int i = pos;
int j = 1;
int next[255];
get_next(T,next);
while(i<=S[0]&&J<=T[0])
{
if(S[i] == T[j])
{
i++;
j++;
if(T[i]!=T[j])
{
next[i] = j;
}
else
{
next[i] = next[j];
}
}
else
{
j = next[j];
}
}
if(j>T[0])
{
return i - T[0];
}
else
{
return 0;
}
}