关于Kmp

Kmp就是在一个模板字符串p中找到和字串t相同的串的位置。

重点在于prefix数组的建立。prefix数组代表了t串每个位置截取当前长度的字串的最大相同前后缀。如:a为0, aa为1, ab为0, aabaa为2, aaaaa为4等等。

由于prefix数组代表最大相同前后缀,那么当我们把字串和模板串对比的时候,如果遇上两个不相等的字符,由于前面都匹配上了,所以我们只要把当前位代表的最大的相同前后缀长度的那一位移动到这里就行了,这样前面的已经匹配上的就不用再匹配一次。

 

 

可以看到上图第5位不同,那么由于第四位最大相同前后缀为1,那么前一位一定相同我们不用再比较,直接移动到第2位

 

 

这样反复进行最后就能找到结果。

(注意写代码时由于字符串由0位置开始,所以为了方便会将整个prefix数组向后移动一位,所以以下说的并不是最后实际的位置)

那么显而易见prefix[0]必然为0,我们用两个指针(此处不是C语言的那个指针),j指向第一位也就是t[0],i指向第二位也就是t[1]。如果i位置的字符等于j位置,那么prefix[i] = j,i和j都向后移动一位继续不相等的时候我们就往前去找这个位置对应的最大相同前后缀的那一位。(原理和Kmp搜寻时的一样,可以少做一些对比)

 

那么上代码:

首先是prefix数组的建立:

void Get_prefix()
{
    prefix[0] = -1;
    int i = 1, j = 0;
    while(i < m){
        if(t[i] == t[j]){
            j++;
            prefix[i+1] = j;//为了方便把整个prefix数组往后移一位,所以是i+1
            i++;
        }
        else{
            if(j > 0){
                j = prefix[j-1];
            }
            else{
                prefix[i+1] = 0;
                i++;
            }
        }
    }
}

然后是KMP主体代码:

void Kmp()
{
    int i = 0, j = 0;
    while(i < n){
        if(j == m - 1 && p[i] == t[j]){
            printf("%d\n", i-j+1);
            j = prefix[j];//继续搜寻,如果只要第一个直接return就行
        }
        if(p[i] == t[j]){
            i++; j++;
        }
        else{
            j = prefix[j];
            if(j == -1){ 
                i++; j++;
            }
        }
    }
}

 

posted @ 2018-07-28 18:25  Lightfall  阅读(104)  评论(0编辑  收藏  举报