KMP演算法初學
阿新 • • 發佈:2020-08-07
具體講解https://blog.csdn.net/v_JULY_v/article/details/7041827
兩個概念得需要知道:
字首:指的是字串的子串中從原串最前面開始的子串,如abcdef的字首有:a,ab,abc,abcd,abcde
字尾:指的是字串的子串中在原串結尾處結尾的子串,如abcdef的字尾有:f,ef,def,cdef,bcdef
如果給定文字串S“BBCABCDABABCDABCDABDE”,和模式串P“ABCDABD”,
普通的方法就是暴力,從頭開始遍歷如果不匹配就讓字串向後平移一位,平且需要重新開始對比,重複此過程直到找到對應的字串,非常耗時。
KMP演算法不需要重新對比,只需要找到最長的公共前後綴然後將字首移至字尾,並且繼續從字串的當前位置開始比較,比如兩個串,主串abbababaabbab,模式串abbaa,我們從1開始遍歷(紅色表示不匹配,藍色表示最長公共字首字尾)
1.abbababaabbab
abbaa
第五位不同,且最長公共字首字尾長度為1,將模式串字首移至對應的字尾上,繼續從第五位開始比較不需要回溯,不斷的重複直到找到對應的子串:
abbababaabbab
abbaa
......(這是我理解的)
next 陣列各值的含義:代表當前字元之前的字串中,有多大長度的相同字首字尾。例如如果next [j] = k,代表j 之前的字串中有最大長度為k
//優化過後的next 陣列求法 void GetNextval(char* p, int next[]) { int pLen = strlen(p); next[0] = -1; int k = -1; int j = 0; while (j < pLen - 1) { //p[k]表示字首,p[j]表示字尾 if (k == -1 || p[j] == p[k]) { ++j; ++k; //較之前next陣列求法,改動在下面4行 if (p[j] != p[k]) next[j] = k; //之前只有這一行 else //因為不能出現p[j] = p[ next[j ]],所以當出現時需要繼續遞迴,k = next[k] = next[next[k]] next[j] = next[k]; } else { k = next[k]; } } }
intKmpSearch(char* s, char* p) { int i = 0; int j = 0; int sLen = strlen(s); int pLen = strlen(p); while (i < sLen && j < pLen) { //①如果j = -1,或者當前字元匹配成功(即S[i] == P[j]),都令i++,j++ if (j == -1 || s[i] == p[j]) { i++; j++; } else { //②如果j != -1,且當前字元匹配失敗(即S[i] != P[j]),則令 i 不變,j = next[j] //next[j]即為j所對應的next值 j = next[j]; } } if (j == pLen) return i - j; else return -1; }