KMP 經(jīng)典的串匹配算法

基本操作之子字符串查找:給定一段長度為N的文本和一個長度為M的模式(pattern)字符串,在文本中找到一個和該模式相符的子字符串。
可以很容易地拓展為找出文本中所有和該模式相符的字符串、統(tǒng)計該模式在文本中的出現(xiàn)次數(shù)、或者找出上下文(和該模式相符的子字符串周圍的文字)的算法。
經(jīng)典應用:查找單詞,海量文本查找。。。

暴力子字符串查找算法

所謂暴力,就是所有可能的地方都比較一遍pattern

int search(string pat,string txt){
    int M = pat.size();
    int N = txt.size();
    for(int i = 0;i<=N-M;i++){
        int j;
        for(j = 0; j<M;j++)
            if(txt[i+j]!=pat[J])
                break;
        if( j==M )
            return i;
    }
    return N;
}

典型的字符串處理應用程序中,索引j增長的機會很少,因此該算法的運行時間與N成正比,最壞情況下,則需要~NM次字符比較。正常的英文文本可能不會出現(xiàn)這樣的情況,但是二進制文本是完全有可能的。
還有一種實現(xiàn)比如顯式回退

for( i = 0, j = 0; i<N && j<M; i++)
{
    if(txt[i] == pat[j]  j++;
    else{ i-=j;j=0;}
}

KMP字符串查找算法

基本思想:當出現(xiàn)不匹配時,就能直銷一部分文本的內(nèi)容,可以利用這些信息避免將指針回退到所有已知的字符之前。
但是要注意,在匹配失敗時,如果模式字符串中的某處可以和匹配失敗處的正文相匹配,那么就不應該完全跳過所有已經(jīng)匹配的所有字符。
所以KMP算法的主要思想是提前判斷如何重新開始查找,而這種判斷只取決于模式本身。

那么我們需要計算字符串f每一個位置之前的字符串的前綴和后綴公共部分的最大長度(不包括字符串本身,否則最大長度始終是字符串本身)。

#define MAX_N 200005

class KMP{
public:
    bool match(char *T, char *P,int n, int m){
        buildNext(P, m);
        int i = 0, j = 0;
        
        while(j < m && i < n){
            if(j < 0 || T[i] == P[j]) { //若匹配
                i++; j++; //則攜手并進
            }
            else{ // P右移, T不回退
                j = next[j];
            }
        }
        return (i - j) <= (n - m);        
    }

private:
    int next[MAX_N];
    void buildNext(char *P, int m){
        int t = next[0] = -1;
        int j = 0;
        while(j < m - 1){    //j來遍歷next數(shù)組
            if(t < 0 || P[j] == P[t]){    //以前綴為目標進行匹配,沒有相等字符串或者匹配成功+1
                j++; t++;
                next[j] =  (P[j] != P[t]) ? t : next[t];  //原本為next[j]=t;如果P[j]==P[t]的話,回溯到next[t]
            }
            else
                t = next[t];    //往前回溯,縮小子串的范圍繼續(xù)比較 
        }
        return;
    }
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容