KMP演算法匹配原理以及C++實現

來源:互聯網
上載者:User

標籤:

原創作品,轉載請註明出處:點我
假設A表示目標字串,A="abababaababacb",B表示匹配模式,B="ababacb"用兩個指標i和j分別表示,A[i-j+1 .... i]與B[1...j]完全相等。也就是說,i是不斷增加的,隨著i的增加j相應的變化,且滿足以A[i]結尾的長度為j的字串正好匹配B串的前j個字元(j當然越大越好),現在需要jianyanA[i+1]和B[j+1]的關係。當A[i+1]=B[j+1]時,i和j各自增加一,什麼時候j=m了,我們就說B是A的子串(B串已經完整了),並且跟根據這使得i值算出匹配的位置。當A[i+1]<>B[j+1],KMP的策略是調整j的位置(減小j值)使得A[i-j+1...i]與B[1...j]保持匹配且新的B[j+1]恰好與A[i+1]匹配。i  = 1  2  3  4  5  6   7  8  9 10 11 12 13  14A = a  b  a  b  a  b  a  a  b  a   b   a   c   bB = a  b  a  b  a  c  bj  = 1  2  3  4  5  6  7當i,j等於5時,A[i+1]跟B[j+1]不相等,這是要縮小j為j‘(也就是要把B字串往右移)。我們發現,j‘必須要使得B[1...j]中的頭j‘個字母和末j‘個字母完全相等,這樣j變成j‘後才能繼續保持i和j的性質。當然,j‘越大越好。當心的j為3時,恰好符合要求。我們可以知道,新的j可以取多少跟i無關,只與B串有關。我們可以預先處理出這樣的一個數組P[j],表示當匹配到B數組的第j個字母而第j+1個字母不能匹配的時候,心的j的最大值是多少。以B="ababacb"為例,解釋P[j]數組的求結果a b a b a c b0 0 1 2 3 0 01、首字元a,一律設為0,即P[1]=02、“ab” 第一個字元為a,最後一個字元為b,不相等,所以長度為0,即P[2]=03、“aba”,頭兩個字串為“ab”,後兩個為"ba",不相同,頭一個字串為a,後一個也為a,相同,所以長度為1,即P[3]=14、"abab",頭兩個為ab,後兩個為ab,相同,頭三個位aba,末尾三個為bab,不同,所以最大長度為2,即P[4]=25、"ababa",頭三個位aba,末尾三個也為aba,頭四個為abab,末尾四個為baba,不同,所以最大長度為3,即P[5]=3以此類推,可以得出數組P[j]  求出了P[j]之後,就可以根據P[j]進行匹配了,還是以上面的A、B為例,匹配過程中用到的幾個變數pattern表示B,Target表示AheadIndex指向A中跟B進行匹配的子串的首字元targetIndex指向A中正在跟B匹配的字元的索引,patternIndex指向B中配對的字元在B中的索引targetIndex等於向右移動的位元加上patternIndex,即targetIndex=headIndex-1+patternIndex第一步、此時,patternIndex= 1,targetIndex= 1,headIndex=1此時pattern[patternIndex] == target[targetIndex],然後patternIndex跟targetIndex增加一,再接著比較是否相同直到targetIndex跟patternIndex為6的時候,pattern[patternIndex] != target[targetIndex]此時,就需要把B向右移動,進行下一次的匹配,那移動多少比較好呢?這就需要根據P[j]來計算由於此時, patternIndex前面的ababa已經匹配了,P[5]=3,前面匹配的字串ababa的長度為5,所以字串pattern向右移動的位元為5-3=2,即pattern向右移動到3,即新的headIndex=headIndex+2=3;而新的patternIndex=P[5]+1=4,即新的patternIndex指向B串中的第四位,targetIndex=headIndex+patternIndex-1=3+4-1=6,所以移動之後的情況如此時,此時pattern[patternIndex] == target[targetIndex],然後patternIndex跟targetIndex增加一,再接著比較是否相同 當patternIndex等於6,targetIndex等於8時,pattern[patternIndex] != target[targetIndex],又要把B串往右移,此時, P[5]=3,前面的ababa已經匹配,長度為5,所以向右移動的位元為5-3=2,此時,headIndex=headIndex+2=3+2=5,patternIndex=P[5]+1=4,指向B串中的第四位,targetIndex=headIndex+patternIndex-1=5+4-1=8,所以targetIndex指向A串中的第八位此時pattern[patternIndex] != target[targetIndex],又要把B串往右移,此時前面的aba已經匹配成功,長度為3,P[3]=1,所以往右移動的長度為3-1=2,移動兩位,此時,headIndex=headIndex+2=5+2=7,patternIndex=P[3]+1=1+1=2指向B串中的第二位,targetIndex=headIndex+patternIndex-1=7+2-1=8,指向A串的第八位此時pattern[patternIndex] != target[targetIndex],又要把B串往右移,此時前面已經匹配的串為a,長度為1,P[1]=0,往右移動的位元為1-P[1]=1-0=1; 此時,headIndex=headIndex+1=7+1=8,patternIndex=P[1]+1=1,指向B串的第一位,targetIndex=headIndex+patternIndex-1=8+1-1=8,指向A串的第八位,此時再一次匹配,就會匹配成功。下面是KMP演算法的C++實現,有點小問題
 1 #ifndef __KMP__H__ 2 #define __KMP__H__ 3 #include <string> 4 #include <vector> 5 using namespace std; 6  7 class KMP{ 8 public: 9              //void static getNext(const string &str,vector<int> &vec);10              int kmp();11             KMP(){}12             KMP( const string &target,const string &pattern):mTarget(target),mPattern(pattern){}13             void setTarget(const string &target);14             void setPattern(const string &pattern);15 private:16             vector< int> mVec;17             string mTarget;18             string mPattern;19             void getNext();20 };21 #endif

下面是原始碼實現

 1 #include "KMP.h" 2 #include <iostream> 3 #include <vector> 4 using namespace std; 5  6  7 //擷取字串str的所有子串中相同子集的長度 8 //比如字串ababacb,分別擷取字串a,ab,aba,abab,ababa,ababac,ababacb中D 9 //最前面和最後面相同的子串的最大長度,比如10 //a:因為aa為a單個字元,所以最前面和最後面相同的子串的最大長度為a011 //aba,最前面一個a和最後面一個元a素a相同,所以值為a1,abab最前面2個ab和最後面兩個ab相同,值為a212 //ababa最前面3個為aaba,最後面3個為aaba,所以值為a313 void KMP::getNext()14 {15       mVec.clear(); //清空?ec16       //vec.push_back(0);//為a了使用方便,vec的第一個資料不用17       mVec.push_back(0); //第一個字元的下一個位置一定是0,比如"ababacb",首字元a的值為018       string::const_iterator start = mPattern.begin();19       string::const_iterator pos = start + 1;20       while(pos != mPattern.end())21       {22             string subStr(start,pos+1); //擷取子字串23             int strLen = subStr.size() - 1;//擷取子串中D前後相同的子子串的最大長度24             do25             {26                    string prefix(subStr,0,strLen); //擷取subStr中D的前面strLen子集27                    string postfix(subStr,subStr.size()-strLen,strLen); //擷取subStr中D的前面?trLen子集28                    if(prefix == postfix)29                    {30                            mVec.push_back(strLen);31                            break;32                     }33                     --strLen;34                     /如果前後相同的子集的長度小於一35                     /說明沒有相同的,則把0壓棧36                     if(strLen < 1)37                        mVec.push_back(0);38              } while(strLen > 0);39 40              ++pos;41        }42 }43 44 void KMP::setPattern(const string &pattern)45 {46       mPattern = pattern;47 }48 49 void KMP::setTarget(const string &target)50 {51       mTarget = target;52 }53 54 55 56 57 int KMP::kmp()58 {59      getNext(); //首先擷取next資料60      int targetIndex = 0;61      int patternIndex = 0;62      int headIndex = 0;//指向跟pattern匹配的Target的第一個元素的索引63      while(patternIndex != mPattern.size() && targetIndex != mTarget.size())64      {65            for(int i = 0; i < mPattern.size()-1;++i)66            {67                   if(mPattern[patternIndex] == mTarget[targetIndex])68                   {69                          ++patternIndex;70                          ++targetIndex;71                          if(mPattern.size()== patternIndex)//如果已經匹配成功,則退出迴圈72                                  break;73                    }74                    else75                    {76                          if(0 == patternIndex)//如果第一個字元就不匹配,則把mTarget左移一位77                                   ++headIndex;78                          else79                          {80                                   headIndex += patternIndex - mVec[patternIndex-1];//由於vector索引從零開始,所以要減去一81                                   patternIndex = mVec[patternIndex-1];//更新patternIndex索引82                          }83                          targetIndex = headIndex + patternIndex;//跟新targetIndex索引84                          break;85                     }86 87             }88       }89 90       return headIndex;91 }

KMP演算法匹配原理以及C++實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.