KMP算法的改进

    技术2022-07-12  70

    KMP算法的改进

    KMP算法已经在极大程度上提高了子符串的匹配效率,但是仍然有改进的余地。

    1. 引入的情景

    下面我们就其中的一种情况进行分析:

    主串T为"aaaabcde…"子串S为"aaaade"

    那么容易求得子串的next[]={0,1,2,3,4}

    下标12345子串aaaadnext01234

    当使用KMP算法进行匹配时,

    由于T[5]!=S[5], 因此子串指针回溯,子串回溯后变为T[5]与S[4]的关系,依然不等, 子串继续回溯子串回溯后变为T[5]与S[3]的关系,依然不等,子串继续回溯子串回溯后变为T[5]与S[2]的关系,依然不等, 子串继续回溯子串回溯后变为T[5]与S[1]的关系,依然不等,子串继续回溯由于子串指针的值为0(j=0),主串和子串的指针同时向前移动一个位置,变为T[6]与S[1]的关系… …

    效果图如下:

    实际上我们可以看出,S[1]=S[2]=S[3]=S[4], 既然S[4]!=T[5], 那么前面的几个根本无需比较。因此KMP 算法可进一步优化的地方便在于此。

    2. 对KMP算法不足的说明

    之所以出现上述问题,个人分析,原因在于:KMP的next数组只分析了当前字符之前的字符串的相似度,而没有把当前字符考虑进去, 从而导致上述没有意义的比较操作。

    那么如何才能把当前字符也考虑进去呢?

    基本原理就是,在需要子串指针回溯时,进行当前位置元素与回溯之后位置元素比较,如果相等,那么就没有必要再进行比较了,子串的指针继续回溯。如此往复

    因此,改进的KMP算法又添加了一个数组nextval, 它是在next基础之上计算出来的。 n e x t v a l [ i ] { n e x t [ i ] , i f   S   [ i   ]   ! =   S   [ n e x t   [ i   ]   ] n e x t v a l [ n e x t [ i ] ] , i f   S   [ i   ]   = =   S   [ n e x t   [ i   ]   ] nextval[i]\begin{cases}next[i], &if\ S\ [i\ ]\ != \ S\ [ next\ [i\ ] \ ] \\nextval[next[i]], &if\ S\ [i\ ]\ == \ S\ [ next\ [i\ ] \ ] \\\end{cases} nextval[i]{next[i],nextval[next[i]],if S [i ] != S [next [i ] ]if S [i ] == S [next [i ] ]

    3. 改进KMP算法实现

    /************************************************************************* > File Name: kmp_pro.c > Author: Toney Sun > Mail: vip_13031075266@163.com > Created Time: 2020年06月27日 星期六 21时07分12秒 ************************************************************************/ #include<stdio.h> #include<string.h> #include<stdlib.h> int getNextVal(char *str, int nextval[]) { int i = 0; int j = -1; if(!str || !nextval){ printf("Parameters can't be NULL or can't be zero\n"); return -1; } nextval[0] = -1; printf("%2.2d ", nextval[0]); while(i < strlen(str)-1){ if(j == -1 || str[i] == str[j]){ i++; j++; /*****************************************/ if(str[i]!=str[j]){ nextval[i]=j; }else{ nextval[i]=nextval[j]; } /*****************************************/ printf("%2.2d ", nextval[i]); }else{ j = nextval[j]; } } printf("\n"); return 0; } int kmp_pro(char *Str, char *match) { int i=0,j=0; int nextval[100] = {0}; int ret =getNextVal(match, nextval); if(ret != 0){ printf("Get nextval error\n"); return -1; } while(i<(int)strlen(Str) && j<(int)strlen(match)){ if(j == -1 || Str[i] == match[j]){ i++; j++; }else{ j = nextval[j]; } } if(j == strlen(match)){ return i - j; }else{ return -1; } } void main(int argc, char *argv[]) { char *str="ababaaaaba"; char *match="aba"; int index = kmp_pro(str, match); printf("-------index=%d------\n",index); match="aaa"; index = kmp_pro(str, match); printf("-------index=%d------\n",index); match="aab"; index = kmp_pro(str, match); printf("-------index=%d------\n",index); }
    Processed: 0.016, SQL: 10