KMP算法(未優化版本,算法導論原版)

kmp是經典的單模式串字符串匹配算法,對於一個字符串在長文本中的匹配很有效。
kmp算法包括兩部分,對模式串的預處理和模式串匹配**

1、模式串預處理
這一部分關鍵在於next數組的構造,相當於對模式串進行kmp匹配。注意,字符串數組與next數組的首字符不存儲信息。
next數組中儲存當該字符的下一個不匹配時,下一步應當跳轉到哪裏,即,到此爲止該字符串的最長公共前綴,後綴的長度。
詳細見代碼註釋
預處理代碼的解釋圖

void next(int *next, char *c)//字符串從c[1]開始賦值
{
    //k爲要比較的字符的前一個的下標,一開始比較c[1]c[2],所以k初始化爲0
    int k = 0;
    //首字符的next值初始化爲0,說明包①含這個字符的字符串前後綴長爲0,②即要比較的字符c[1]的前一個
    next[1] = 0;//注意next數組值的兩層含義
    //一開始比較c[1]c[2],i初始化爲2,
    for (int i = 2; i < strlen(c); i++)//next數組最後一個的值比strlen值小一,所以不要取等
    {
        //當k可以回溯且不匹配時,讓k回溯
        //k初始化爲0,保證可回溯,即k>0
        while (k > 0 && c[i] != c[k + 1])
        {
            k = next[k];//對前串來說a[k]是a1中前綴的最後一個字符所在位置
        }
        if (c[i] == c[k + 1])//若匹配則k+1,
            k++;
        next[i] = k;//包含i的字符串的前綴長=加過1的k。
    }
}

2、kmp匹配部分
原理與模式串匹配相似,只不過是兩個字符串的匹配

void kmp(char *t, char *p)//t爲長串,p爲短串
{
    int *next;
    next = (int *)malloc(sizeof(int)*(strlen(p)+1));
    buildnext(next, p);
    int k = 0;//k爲要比較的字符的前一個的下標,一開始比較模式串中的c[1],k初始化爲0
    for (int i = 1; i < strlen(t); i++)//長串的最後一個字符的下標爲長度-1
    {
        while (k>1 && p[k + 1] != t[i])
            k = next[k];
        if (p[k + 1] == t[i])
            k++;
        if (k == strlen(p)-1)
        {
            printf("開始下標爲%d\n", i - strlen(p)+1+1);
            k = next[k];//尋找下一個匹配串
        }
    }

這種原始的kmp算法有一個弊端,當字符串重複性很高時(例如ababababag),它的效率和樸素匹配沒啥區別了。因爲當重複性很高時,如果有一位失配,那麼再向後移動仍然失配。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章