淺談數據結構之KMP(串中的模式匹配算法)


  KMP算法是一種模式匹配算法的改進版,其通過減少匹配的次數以及使主串不回朔來減少字符串匹配的次數,從而較少算法的相應代價,但是,事件萬物是普遍歸中的,KMP算法的有效性也是有一定的局限的,我將在本文的最后也討論這個算法的局限性。

  一般的匹配算法:

 

  傳統匹配算法

KMP基本概念引入:

  但是,其實我們會發現,上面的中間兩個匹配步驟是沒有必要的,因為他們的第一個匹配字母就不相同,完全沒有可比性,而當我們在第四次匹配的時候,其實我們從模式串中就可得知,只有當模式串滑到這個地方的時候,它的匹配才是最有價值的,因為從模式串中我們可以得知,最后一個C的前一個字母是a,而在模式串中的第二個字母b的前一個字母也是a,再無其他,從第一步匹配的結果我們可以得知,模式串中的最后一個字母c與主串中的b匹配失敗(讀者們是否注意到,我們前面提到的,這個c的前一個字母是a哦), 而從模式串中我們可以得知,即我們完全可以跳過上面匹配步驟的中間的兩步,那是否讀者在擔心中間會錯過原本可以匹配的呢,完全不必擔心,因為在我們的模式串中就記錄了,前面就連一個能和a進行匹配的字母都沒有。
  那么,當某一輪匹配失敗時,模式項的滑動位置如何確定,即模式項中的那一項來和主串的的b(黃色格子內)對齊,從而省略中間的比較項,我們可以將這一項的index設置為K,如上的模式項,K為2   注意在串中,數組的第一項是用來記錄數據個數的。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

如上所述,KMP算法的關鍵,即根據模式串找到那個K(下面列出K所需要滿足的條件)(當主串中第i個字符與子串中第j個字符失配時):

設主串為:s1s2……sn  子串為:p1p2……pn

則K的取值應滿足:

p1

p2

----------------------》》》》》》》》》》》》》》》pr

 

歸根結底,找模式串與串頭重復的子串:

實例:

   KMP

 

那么:如何找到模式串中的每一個元素的K,也即如圖中的next數組:

  代碼敬上:

void get_next(SString T,int next[])
 { /* 求模式串T的next函數值並存入數組next 算法 4.7 */
   int i=1,j=0;
   next[1]=0;
   while(i<T[0])
     if(j==0||T[i]==T[j])
     {
       ++i;
       ++j;
       next[i]=j;
     }
     else
       j=next[j];  /*精髓之處  當前面已經有了相似的比較的時候,直接借用前面的結果    兩個大體的環境相似,則這兩個大體的環境間就會存在相同的匹配環境,即已經記錄的環境,如果錯過了一些已經匹配了子串,則會導致K值比實際的要小,即后面的匹配必須依賴前面的匹配結果*/
 }

  上面代碼解釋:

          KMP2

       1:j=0時,i和j都要相加並給next賦值

       2:T[i] = T[j] ,i和j都要相加並給next賦值

       如果上面兩個都不滿足,則需要將 j 往前指向,那么問題就來了,為什么不直接 j = 1,而需要將 next[j]的值賦給 j 呢,其實就如我在代碼中所講,不妨也舉個栗子說明一下。

       KMP3

       其實可以總結為一下幾點,K的目的是定位偏移量的index,失配項的前面有幾個與模式項的頭部相等的,K就為這些數加1,而其實這幾個數,正是我們所要跳過的。

     

   KMP算法的劣勢,其實,從尋找K的過程中我們就可以看出,KMP算法重度依賴模式串與主串存在許多部分匹配,不然~~~~~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM