KMP pattern matching, find substring

Code parsing

void cal_next(char *ptr, int *next, int plen)
{
    next[0] = -1;
    int k = -1;
    for (int i = 1; i <= plen-1; i++)
    {
        while (k > -1 && ptr[k + 1] != ptr[i])
        {
            k = next[k];
        }
        if (ptr[k + 1] == ptr[i])
        {
            k = k + 1;
        }
        next[i] = k;
    }
}
一.void cal_next(char *ptr, int *next, int plen)

1.for(int i=1;i<plen-1;i++);next,next[i];中的i为什么从1开始,plen-1结束?

因为i=1~plen-1,next[0]=-1;
所以数组next即可取遍0~plen-1的元素,长度为plen

2.while(k>-1&&ptr[k+1]!=ptr[i])中的while可以改为if吗?
因为每一次发现不匹配可以向更小的开始匹配,不止是一次

3.k=next[k];

k将变为更小的(小字符串内部的)最大相同前后缀长度,比较时,自然是在原有的基础上变为ptr[k+1]与字符串末端比较,而比较的基础是:前后缀是相同的,即ptr[k+1]接在前缀后,ptr[i]接在后缀后,如果相同,便可以 k++,否则,以此类推,此乃递归思想或者叫数学归纳思想(这两种思想到底有什么区别呢?我也不知道.冒昧地问一下...
明白next[k]中下标是k时的含义吗?)

4.next[0]=-1;int k=-1中的两个-1,,意义何在?
对于while(k>-1&&ptr[k+1]!=ptr[i])中的k为初值-1,此时k+1=0,str[k+1]==str[0];
对于
while(k>-1&&ptr[k+1]!=ptr[i])中的k=0时,若ptr[k+1]!=ptr[i],则k=next[k]==-1;又化为初值了,这只有问题中的两个-1同时存在时才能达到这种效果

5.为什么k>next[k]?

首先要明确,比较的前提是k>-1(不是因为next[-1]不存在,而是因为while(k>-1&&ptr[k+1]!=ptr[i])中有这个条件);其次要明白next[k]中下标是k时的含义:就是在原来的,有前后缀相同的小字符串长度内部,再找一个更小的,有前后缀的,更小字符串的,前后缀想同的长度-1(这里的-1是出于对字符数组的关怀);在这两个的基础上,就有了k>next[k]的本质理解

6.k=next[k]能改为k--吗?

咋一看,问题不大,效率降低了而已,其实,很危险...举个粒子吧:abcd abce abcd abcc
真实匹配为-1,结果却为2;离谱的很,因为它的二次检索不是建立在“小字符串”(前面已经介绍该词的来源了)的基础上

7.该函数实现了什么功能?

宏观来观察一下,你会发现,该函数使用来得到next数组的,这是理解该函数的前提条件;
该数组的含义是,对于字串的不同字符串长度,对应的,前后缀字符串相同的,最长的长度减一(出于对数组下标的尊重,才要减的一)

km²

int KMP(char *str, int slen, char *ptr, int plen)
{
    int *next = new int[plen];
    cal_next(ptr, next, plen);
    int k = -1;
    for (int i = 0; i < slen; i++)
    {
        while (k >-1&& ptr[k + 1] != str[i])
            k = next[k];
        if (ptr[k + 1] == str[i])
            k = k + 1;
        if (k == plen-1)
            return i-plen+1;
    }
    return -1;  
}

二.int KMP(char *str, int slen, char *ptr, int plen)

1.int *next = new int [plen]无需释放?

至于是无需释放还是自动释放,现在自身能力有限,我无法解释,期待你在评论区赐教

 

2.通过比较两个函数,不同点是?有些虽相同,但功能也有不同的,又是?

1..while(k>-1&&ptr[k+1]!=ptr[i])改为while(k>-1&&ptr[k+1]!=str[i])

.讲母串作为“后缀”去理解,再结合函数cal_next(),问题就迎刃而解了;

2..k=next[k]

.貌似功能不变,其实,也差不多,还是要记住,把母串当作后缀来思考会更省事

3.。if(k==plen-1)

.匹配度达百分之百是,就好了,此处比较简单,不啰嗦了

测试

    char *str = "bacbababadababacambabacaddababacasdsd";
    char *ptr = "ababaca";
    int a = KMP(str, 36, ptr, 7);
    return 0;

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325340841&siteId=291194637