字符串的模式匹配


問題描述:如果子串T在主串中存在,則返回存在的位置,如果不存在,則返回-1。

1.基本方法

 從主串的第pos位置字符開始和模式子串字符比較,如果相等,則繼續逐個比較后續字符;否則從主串的下一個字符起再重新和模式子串的字符比較。直到找到匹配字符串或者是主串結尾。

偽代碼如下:

 

Index(T,S,pos)
    i <- pos
    j <- 1
  while i<=length[T] and j<=length[S] 
        if T[i]=S[j]
              i++
              j++
        else 
              i <- i-j+2
              j <- 1
   if j> length[S] 
     return i-lenght[S]
    else 
    return -1;

 

例如,主串T為:ababcabababab,子串為ababa,上述過程如下圖所示。

 

 源代碼如下:

/*
檢測從主串T的pos位置開始,是否有和子串S匹配,如果有返回匹配開始位置,如果沒有,返回-1
T:主串
S:子串
tlength:主串長度
slength:子串長度
pos:主串開始位置
*/
int Index (char T[],char S[],int tlength,int slength,int pos)
{
    int j=0,i=pos;
    while(i<tlength&&j<slength)
    {
        if(T[i]==S[j])
        {
            i++;
            j++;
        }
        else
        {
            i=i-j+1;
            j=0;
        }
    }
    return j==slength?i-slength:-1;

}

 

 運行結果如下:

完成源代碼見文章最后!

2.KMP算法

     由上述基本方法匹配過程中,很多次的比較都沒有意義的,比如當第一個主串的c與子串中的a不匹配時,下一次的 主串的b和子串的a(第一個)的比較可以通過分析子串的特點直接跳過這次比較。KMP算法就是為了告訴我們,我們應該每當一趟匹配過程中出現比較不等時,我們不需要回溯i指針。而是利用已經得到的“部分匹配”的結果將模式子串想右“滑動”盡可能遠的距離,然后繼續比較。那么我們應該如何確定這個盡可能遠的距離哪?

     我們通過分析子串P1P2..Pm的特點,可以得出這個“盡可能遠的距離的計算方法”。

     我們假設主串S1S2...Sn和子串P1P2...Pm在主串i和主串j位置不匹配,我們假設我們希望下次子串k(k<j)位置與主串i位置進行比較,即

          P1P2...Pk-1=Si-k+1...Si-1

     由於在匹配過程中主串中的第i和子串中的第j和不相等,也就是說子串位置j前面的所有都匹配了,即:

                  Pj-K+1...Pj-1=Si-k+1...Si-1

      由上面兩個等式的:

                 P1P2...Pk-1=Pj-K+1...Pj-1

     也就是說,要想在當不匹配時,子串向右滑動最遠距離,只要找到子串中滿足上式的最大k值即可,

   我們用next[j]表示當模式子串中第j個字符與主串中相應的字符“失配”時,在模式中需要重新和主串中該字符比較的字符的位置。

   

 

在求得next后,匹配過程進行如下:

假設以指針i和j分別指示主串和模式子串中正待比較的字符,令i的初值為pos,j的初值為0.若在匹配過程中Si=Pj,則i和j分別加1,否則,i不變,而j退到next[j]的位置再比較,若相等,則指針各增1,否則,j再退到下一個next值的位置,依次類推,直到下面兩種可能:一種是j退到某個next值的字符比較相等,則指針各自增1,繼續進行匹配;另一種是j退到0(即模式的第一個字符失配),則此時需要將模式繼續向右滑動一個位置,即從主串的下一個字符Si+1起和模式重新開始匹配。

舉例說明:

例如,主串T為:acabaabaabcacaabc,子串為abaabcac,上述過程如下圖所示。

首先計算出zi串next[]={0,1,1,2,2,3,1,2},匹配過程如下:

實現程序如下:

int KMP_Index(char T[],char S[],int tlength,int slength,int pos)
{
    int *next=(int*)malloc(slength*sizeof(int));
    KMP_Next(S,next,slength);

    int j=-1,i=pos-1;
    while(i<tlength&&j<slength)
    {
        if(j==-1||T[i]==S[j])
        {
            i++;
            j++;
        }
        else
            j=next[j];
    }
    return j==slength?i-slength:-1;


}

 

 程序源代碼實現:StringPatternMatching.zip

 


免責聲明!

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



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