1. 程式人生 > >第四章 串和數組 (主要kmp算法)

第四章 串和數組 (主要kmp算法)

bsp 移動 算法 匹配 方便 void 不可 順序 聲明

第四章

題目:串的模式匹配

給定一個主串S(長度<=10^6)和一個模式T(長度<=10^5),要求在主串S中找出與模式T相匹配的子串,返回相匹配的子串中的第一個字符在主串S中出現的位置。

(用KMP算法,就是不用再回溯,

最前面的k個字符和j之前的最後k個字符是一樣的:P[1~ k] == P[j-k ~ j-1])

1、先定義一個串的順序存儲結構,因為不需要出插入和刪除操作,所以選用了順序存儲

typedef struct {
    char ch[maxlen + 2];
    int length;
}sstring;

2、為了方便自己對於kmp的理解,所以用以下代碼來實現數組下標從1開始

void add(sstring &s, char temp[]) {   
    s.ch[0] =  ;
    strcat(s.ch, temp);
    s.length = strlen(s.ch) - 1;
}

3、按照題目要求寫了一部分主函數

  int main()
{ int result = 0; cin >> temp; add(s, temp); cin >> temp; add(t, temp);
需要一個求位置的函數
求位置時在回溯過程中需要一個知道回溯到哪裏的函數
}

發現需要兩個函數,於是開始寫下面的函數

4、用一個函數來求模式串的next函數並存入數組nextval。

其中有個初始化如下,我起初不理解,後面想明白了:j已經在最左邊了,不可能再移動了,所以這時候要應該是i指針後移

nextval[1] = 0;

找到next函數的主要過程:

while (i < t.length) {  //t為模式串

        if (j == 0 || t.ch[i] == t.ch[j]) {  //相同則繼續往後移,找到最長相同前後綴
            j++;
            i++;

            
if (t.ch[i] != t.ch[j]) { //前面已經+1,匹配下一個是否相等, nextval[i] = j; //如果不同 把j位置給next } else { //如果相同 nextval[i] = nextval[j]; //則i 的位置等於j的位置,最長相同前後綴同時加 } } else //如果不等,則重置j j = nextval[j];//next[j]為之前最長相同前後綴 }

主要是:

當T[i] != P[j]時,有T[i-j ~ i-1] == P[1 ~ j],由P[1 ~ k] == P[j-k ~ j-1] —> 必然:T[i-k ~ i-1] == P[1 ~ k]

5、利用模式串T的next函數求T在主串S中第幾個字符之後的位置。

1)表示位置相同的變量

int result = 0;

2)如果相同則右移

    if (j == 0 || s.ch[i] == t.ch[j]) { 
            j++;
            i++;
        }

3)不同則回溯

else {
            j = nextval[j]; 
        }

4)匹配成功時,result即為第一個字符出現的位置

if (j > t.length) {  //當最後匹配成功就是比主串多1時
        result = i - t.length;
    }

6、寫完函數後寫函數聲明

oid add(sstring &s, char temp[]);
void getnext(sstring T, int next[]);
int KMP(sstring s, sstring t, int next[]); 

7、補充主函數

int main()
{
    int result = 0;
    cin >> temp;
    add(s, temp);
    cin >> temp;
    add(t, temp);
    getnext(t, nextval);
    result = KMP(s, t, nextval);
    cout << result;
    return 0;
}

第四章 串和數組 (主要kmp算法)