KMP演演算法的簡述
每一次比較時,當子串與主串不相等的時候,主串的指標不回溯,而是通過next函數所求得的值當作下一位子串開始比較的位置。(即儘可能地向右邊滑動一段的距離,從而減少比較的次數)。
int Index_KMP(SString *S, int pos, SString *T) {
int next[MAXSIZE] ;
Get_Next( T, next);
int i = pos, j = 1;
while(i <= S->len && j <= T->len) {
if(S->data[i] == T->data[j] || j == 0) {
//j == 0是一個判斷條件,當子串匹配到第一個字元的時候都沒有匹配
//子串與主串的指標都要向後移動,重新從頭開始進行匹配
++i;
++j;
} else {
j = next[j];
}
}
if(j > T->len)
return(i - T->len);
else
return 0;
}
next演演算法的描述
首先next函數是基於遞推的思想的,KMP演演算法是基於next函數來實現的。
next的函數值,由上述的定義可以得到next[1] = 0,假設next[j] = k,說明最長的匹配的真字首子串和字尾子串的長度為k-1,那麼next[j+1]有以下兩種情況:
(1)當T[j] = T[k]時,也就是說當T[j]失配的時候重新找到的匹配的位置與他相等,也就是說現在子串前k+1個字元相等,所以next[j+1]時,值為k+1,即next[j+1] = next[j] +1,一定要注意next值的定義。
(2)當T[j] != T[k]時,這時候求next值的問題我們可以看作是一個模式匹配的問題,匹配的過程中模式串既是主串又是模式串。其中1<k’<k<j,相當於如果當前的失配,那麼就向前一直找直到下一位與當前主串的字元相匹配,或者直到子串的第一位還是不匹配,那麼主串和子串同時向後移動,這就是while迴圈的條件,具體如下:
①:若T[j] = T[k’],且k’ = next[k],那麼next[j+1] = k’+1,即next[j+1] = next[next[k]]+1.
②:若T[j] != T[k],則繼續比較T[j]和T[next[k’]],即比較T[j]和T[next[next[k]]].
然後一直這樣下去直到k = 0都沒有成功,則next[j+1] = 1.
void Get_Next(SString *T,int *next) {
int i = 1, j = 0;
next[1] = 0;
while(i < T->len) {
if(j == 0 || T->data[i] == T->data[j]) { //相等時,next的值等於j+1
++i;
++j;
next[i] = j;
} else {
j = next[j];//往前尋找更小的匹配的子串
}
}
}
nextval演演算法的描述
這是基於next的演演算法進行的,彌補next演演算法的缺陷的。
主要解決了模式串中大量連續重複的字元,nextval函數減少了主串的無用比較的次數
假設主串為:‘aaabaaaab’ 子串為:'aaaab’則對應的next函數值為下:
void Get_NextVal(SString *T, int *next, int *nextval)
{
int j = 2;//j = 1時,nextval[1]的值預設為 0所以從2開始
nextval[1] = 0;
Get_Next( T, next);
while(j <= T->len)
{
if(T->data[j] == T->data[next[j]])
{
nextval[j] = next[next[j]];
}
else{
nextval[j] = next[j];
}
j++;
}
}