kmp演算法02

來源:互聯網
上載者:User

kmp演算法
一種改進的字串匹配演算法,由D.E.Knuth與V.R.Pratt和J.H.Morris同時發現,因此人們稱它為克努特——莫裡斯——普拉特操作(簡稱KMP演算法)。
完全掌握KMP演算法思想

      學過資料結構的人,都對KMP演算法印象頗深。尤其是新手,更是難以理解其涵義,搞得一頭霧水。今天我們就來面對它,不將它徹底搞懂,誓不罷休。
      如今,大夥基本上都用嚴蔚敏老師的書,那我就以此來講解KMP演算法。(小弟正在備戰考研,為了節省時間,很多課本上的話我都在此省略了,以後一定補上。)

      嚴老的《資料結構》79頁講了基本的匹配方法,這是基礎。先把這個搞懂了。
      80頁在講KMP演算法的開始先舉了個例子,讓我們對KMP的基本思想有了最初的認識。目的在於指出“由此,在整個匹配的過程中,i指標沒有回溯,”。
我們繼續往下看:
現在討論一般情況。
假設 主串:s: ‘s(1)  s(2)  s(3) ……s(n)’ ;   模式串 :p: ‘p(1)  p(2)  p(3)…..p(m)’
把課本上的這一段看完後,繼續

現在我們假設 主串第i個字元與模式串的第j(j<=m)個字元‘失配’後,主串第i個字元與模式串的第k(k<j)個字元繼續比較

此時,s(i)≠p(j),  有

主串:               S(1)……  s(i-j+1)…… s(i-1)   s(i) ………….
                                || (相配)   ||       ≠(失配)
匹配串:                        P(1) …….  p(j-1)   p(j)

由此,我們得到關係式
          ‘p(1)  p(2)  p(3)…..p(j-1)’   =    ’ s(i-j+1)……s(i-1)’

由於s(i)≠p(j),接下來s(i)將與p(k)繼續比較,則模式串中的前(k-1)個字元的子串必須滿足下列關係式,並且不可能存在  k’>k  滿足下列關係式:(k<j),
          ‘p(1)  p(2)  p(3)…..p(k-1)’   =    ’ s(i-k+1)s(i-k+2)……s(i-1)’

即:

主串:        S(1)……s(i-k +1) s(i-k +2) ……s(i-1)     s(i) ………….
                        || (相配)  ||           ||       ?(有待比較)
匹配串:                P(1)      p(2)    …… p(k-1)    p(k)

現在我們把前面總結的關係綜合一下

有:

S(1)…s(i-j +1)…  s(i-k +1) s(i-k +2)  ……    s(i-1)     s(i) ……
           || (相配)  ||         ||               ||         ≠(失配)
           P(1) ……p(j-k+1)   p(j-k+2)  …....   p(j-1)    p(j)
                      || (相配)  ||               ||          ?(有待比較)
                      P(1)       p(2)    …….    p(k-1)      p(k)

由上,我們得到關係:
‘p(1)  p(2)  p(3)…..p(k-1)’   =    ’ s(j-k+1)s(j-k+2)……s(j-1)’

接下來看“反之,若模式串中存在滿足式(4-4)。。。。。。。”這一段。看完這一段,如果下面的看不懂就不要看了。直接去看那個next函數的來源程式。(虛擬碼)

K 是和next有關係的,不過在最初看的時候,你不要太追究k到底是多少,至於next值是怎麼求出來的,我教你怎麼學會。
課本83頁不是有個例子嗎?就是  圖4.6
你照著來源程式,看著那個例子慢慢的推出它來。看看你做的是不是和課本上正確的next值一樣。
然後找幾道練習題好好練練,一定要做熟練了。現在你的腦子裡已經有那個next演算法的初步思想了,再回去看它是怎麼推出來的,如果還看不懂,就繼續做練習,做完練習再看。相信自己!!!

附:

KMP演算法尋找串S中含串P的個數count
#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;

inline void NEXT(const string& T,vector<int>& next)
{
    //按模式串產生vector,next(T.size())  
    next[0]=-1;           
    for(int i=1;i<T.size();i++ ){
        int j=next[i-1];
        while(T!=T[j+1]&& j>=0 )
         j=next[j] ;  //遞推計算
        if(T==T[j+1])next=j+1;
        else next=0;  //
    }  
}
inline string::size_type COUNT_KMP(const string&  S,
                    const string&  T)
{
    //利用模式串T的next函數求T在主串S中的個數count的KMP演算法
    //其中T非空,
    vector<int> next(T.size());
    NEXT(T,next);
    string::size_type index,count=0;  
    for(index=0;index<S.size();++index){     
        int pos=0;
        string::size_type iter=index;
        while(pos<T.size() && iter<S.size()){
            if(S[iter]==T[pos]){
                ++iter;++pos;
            }
            else{
                if(pos==0)++iter;             
                else pos=next[pos-1]+1;
            }  
        }//while end
        if(pos==T.size()&&(iter-index)==T.size())++count;
    } //for end
    return count;
}
int main(int argc, char *argv[])
{
    string S="abaabcacabaabcacabaabcacabaabcacabaabcac";
    string T="ab";
    string::size_type count=COUNT_KMP(S,T);
    cout<<count<<endl;

  system("PAUSE");
  return 0;
}

補上個Pascal的KMP演算法源碼

PROGRAM Impl_KMP;
USES
    CRT;
CONST
     MAX_STRLEN = 255;
VAR
   next         : array [ 1 .. MAX_STRLEN ] of integer;
   str_s, str_t : string;
   int_i        : integer;
Procedure get_nexst( t : string );
Var
   j, k : integer;
Begin
     j := 1; k := 0;
     while j < Length(t) do
     begin
          if ( k = 0 ) or ( t[j] = t[k] ) then
          begin
               j := j + 1; k := k + 1;
               next[j] := k;
          end
          else k := next[k];
     end;
End;
Function index( s : string; t : string ) : integer;
Var
   i, j : integer;
Begin
     get_next(t);
     index := 0;
     i := 1; j := 1;
     while ( i <= Length(s) ) and ( j <= Length(t) ) do
     begin
          if ( j = 0 ) or ( s = t[j] ) then
          begin
               i := i + 1; j := j + 1;
          end
          else j := next[j];
          if j > Length(t) then index := i - Length(t);
     end;
End;
BEGIN
     ClrScr;
     Write(s = );
     Readln(str_s);
     Write(t = );
     Readln(str_t);
     int_i := index( str_s, str_t );
     if int_i <> 0 then
     begin
          Writeln( Found , str_t, in , str_s, at , int_i, . );
     end
     else
         Writeln( Cannot find , str_t, in , str_s, . );
END.
index函數用於模式比對,t是模式串,s是原串。返回模式串的位置,找不到則返回0

 

 
 
  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.