KMP算法next数组计算--字符串方式

这里在说明求解KMP算法next数组时假设各位看官已经知道该算法的目的,以及朴素模式匹配方法;

数据结构书籍中在讲字符串时都会提到KMP算法,KMP算法是一种字符串模式匹配算法,因为朴素模式匹配算法往往需要耗费很多时间,而且在匹配过程中做了很多多余的工作,因此提出KMP算法。
KMP算法中很重要的一步是计算模式串的next数组,一般书籍中都直接给了一段程序如下:

void get_next(String T, int *next){
    int i=1;
    int j=0;
    next[1]=0;
    while(i<T[0]){
        if(j==0 || T[i]==T[j]){
            ++i;
            ++j;
            next[i]=j;
        }
        else
            j=next[j];    //若字符不相同,则j值回溯
    }
}

这段代码返回的就是字符串T的next数组,代码中T[0]中存放字符串T的长度,代码参考书籍《大话数据结构》。
当然,网上也有很多类似的代码,但似乎在理解层面上都不够简单(大概是我太愚,能明白求解思路,但是在很难接受这种写法…),下面来说一种自己理解之后写的求next数组的思路。


为了说明我的思路,采用一个简单的例子来辅助说明,例如求模式串T“ababaaaba”的next数组,
首先,next数组结果如下:
j 123456789
模式串T ababaaaba
next[j] 011234223

1)当j=1时,next[1]=0;
2)当j=2时,next[2]=1;
3)当j=3时,next[3]=1;
4)当j=4时,j由1到j-1的串是“aba”,由于前缀字符“a”与后缀字符“a”相等,所以next[4]=2;
5)当j=5时,j有1到j-1的串是“abab”,由于前缀字符“ab”与后缀字符“ab”相等,所以next[5]=3;
6)当j=6时,j由1到j-1的串是“ababa”,由于前缀字符“aba”与后缀“aba”相等,所以next[6]=4;
以此类推…

从上面推导
1、首先可以确定next[1]=0,next[2]=1(假设next数组从下标1开始记录next数组值);
2、然后,第n位next值是由前n位的T串来判断,最大前缀子串T[1~n-1],与之对比的即是T[2~n],若相等,next值为n;
3、若不等,接着判断T[1~n-2]与子串T[3~n],也就是减少了子串的长度,直至前缀子串为1个,对比后结束;

所以代码段的写法可以是:令一个字符串s1=T[1~n-1],字符串s2=T[2~n],直接用==判断s1,s2是否相等,相等→next=(n-1)+1;若不相等,则s1和s2的子串长度减1,判断s[1~n-2]==s[3~n],若相等则next=(n-2)+1,若不相等,继续减少子串长度对比,直至该次循环结束。

个人认为这种思路可能比较好理解KMP算法中求解next数组的过程,可能我没有表述清楚的我的意思,或者理解有欠缺,欢迎提出见解;以下是求next数组的代码:

void compute_next(const string str1, int *next){
    //由分析可知next数组一定是0,1开头
    next[0] = 0;
    next[1] = 1;
    //t1用来保存从头到尾的子串,t2用来保存从尾到头的字串
    string t1, t2;
    for (int i = 2; i < str1.size(); ++i){
        //flag是标志位,用来说明是否出现相等的字串
        int flag = 0;
        for (int j = i-1; j>=1; --j){
            //函数assign(const string &s,int start,int n)把字符串s中从start开始的n个字符赋给当前字符串
            t1.assign(str1, 0, j);
            t2.assign(str1, i - j, j);
            if (t1 == t2){
                flag = 1;
                next[i] = j+1;
                break;
            }
        }
        if (flag == 0)
            //若多个子串对均不相等,next数组值为0
            next[i] = 1;
    }
}

这里只说明了KMP算法中next数组的求解思路,nextval数组求解应该也可以类似求解;这里并没有继续谈KMP的原理和实现,有兴趣可以找找别的blog,有很多详解。
如果您发现错误或者有别的想法,欢迎回复~

你可能感兴趣的:(数据结构,算法)