[String,算法]字符串匹配的KMP算法

[String,算法]字符串匹配的KMP算法:

       字符串匹配的KMP算法是由KnuthMorris Pratt三位教授共同发明,其无回溯算法的精巧程度令人叹为观止.

       网上相关的参考:

       http://mhss.nease.net/string/KMP.html

      

       下面给出我的实现,算法的精华是代码背后的分析,这里就不再详述了,尤其是复杂度分析相当有难度.具体请参考相关的资料.

       1算法思路:

       matchStr中找是否含有patternStr子串: (这里字符串的实现用的是字符串的顺序表示)

       1.a)外层的无回溯层:

       matchStrpatternStr进行比较:

1)  如果patternStr的当前位置与matchStr的当前位置不匹配:

1.1)patternStr的当前位置为patternStr的首位置,则matchStr的位置直接加1.

1.2)patternStr的当前位置不为patternStr的首位置,则matchStr的位置停在当前位置,patternStr的下标回溯到前面的一个恰当位置,利用next数组进行回溯.

       2) 如果patternStr的当前位置与matchStr当前位置匹配,则patternStrmatchStr的位置均前进1.

       3)当patternStrmatchStr的长度到达其长度时,跳出,否则继续做1,2.

       4)如果matchStr达到其长度,则输出找到的位置,matchPos-patternPos+1.

          如果patternStr达到其长度,则输出没有找到的信息.

 

 

       1.b)Next数组的实现思路:

       Next数组主要是标志出一个字符数组的当前位置的最大真前,真后子缀的下标位置,这里采用了一个改进算法,为了配合1.2里的工作,next数组里的下标尽可能的往前移动.

       这一部分对应的程序段为:

       if(patternStr->c[i]==patternStr->c[k])//make the match quicker.

                     nextArr[i]=nextArr[k];

              else

                     nextArr[i]=k;

 

 

在真前与真后子缀的查找的算法同样有技巧:

       对于patternStr里的第i个位置,如果它的前缀数组的位置值为k,则下一个位置的前缀数组的最大位置只有可能为k+1,成立条件为next[i]==next[k],如果没有找到,则下一个位置的在前缀数组中的值为-1.

       这一部对应的程序段为:

       while(k>=0&&patternStr->c[i]!=patternStr->c[k])

                     k=nextArr[k];

                     //exit1:k=-1;    exit2:p->c[i]=p->c[k],has true pre and rear zi zhui.

      

 

 

当这些算法的细节都了解清楚后,你对KMP的实现已基本没有问题的,就像我一样,但对其算法的正确性,效率的分析还是得下一翻工夫才能真正领悟.

 

 

数据结构定义:

顺序型字符串:     

#define STRING_LEN 15000

       /*---Start of SeqStirng---*/

       struct SeqString;

       typedef struct SeqString* PSeqString;

       struct SeqString

       {

              char c[STRING_LEN];

              int len;

       };

 

 

/*Core Algorithm:KMP Alogorithm*/

int kmpMatch1(PSeqString sourceStr,PSeqString patternStr)

{

       int* preArr;

       int lenPre;

       int pos=-1;

       int pScr,pMatch;

      

       int i;

 

 

       assertF(sourceStr!=NULL,"in kmpMatch,pass in sourceStr is null/n");

       assertF(patternStr!=NULL,"in kmpMatch,pass in patternStr is null/n");

      

       lenPre=patternStr->len;

      

       preArr=(int*)malloc(sizeof(int)*lenPre);

       assertF(preArr!=NULL,"in kmpMatch,preArr mem apply faillure/n");

      

       makeNext(patternStr,preArr);

 

 

      

       /*Core Algorithm of KMP*/

       pScr=0;

       pMatch=0;

       while(pScr<=sourceStr->len-1&&pMatch<=patternStr->len-1)

       {

              if(pMatch==-1||sourceStr->c[pScr]==patternStr->c[pMatch])

              {     //current pos has no match||current pos has temp match

                     pScr++;

                     pMatch++;

              }

              else

              {

                     //not match,roll back the next arr.

                     pMatch=preArr[pMatch];

              }

       }

      

       if(pMatch!=patternStr->len)

              pos=-1;

       else

              pos=pScr-pMatch;

      

       return pos;

}

 

 

 

 

void makeNext(PSeqString patternStr,int* nextArr)

{

       int i,k;

       k=-1;

       i=0;

 

 

       nextArr[0]=-1;

       while(i<patternStr->len-1)

       {

              while(k>=0&&patternStr->c[i]!=patternStr->c[k])

                     k=nextArr[k];

              //exit1:k=-1;    exit2:p->c[i]=p->c[k],has true pre and rear zi zhui.

             

              i++;//move to current valued pos.

 

 

              k++;//next arr num adjust,

 

 

              if(patternStr->c[i]==patternStr->c[k])//make the match quicker.

                     nextArr[i]=nextArr[k];

              else

                     nextArr[i]=k;

       }

}

 

 

为了便于对比,给出一个简单的回溯型的匹配算法的实现:

int simpleMatch(PSeqString sourceStr,PSeqString patternStr)

{

       int i,j;

       int pos;

       int flag;

 

 

       assertF(sourceStr!=NULL,"in simple match,sourceStr is null/n");

       assertF(patternStr!=NULL,"in simple match,patternStr is null/n");

 

 

       flag=0;

       j=0;

       i=0;

      

       while(i<sourceStr->len)

       {

              while(patternStr->c[j]==sourceStr->c[i]&&j<patternStr->len)

              {

                     i++;j++;

              }

             

              if(j==patternStr->len)

              {

                     flag=1;

                     break;

              }

              else

              {

                     i=i-j+1;

                     j=0;

              }

       }

      

       if(flag)

              pos=i-j;

       else

              pos=-1;

 

 

       return pos;

}

 

 

源码下载: (测试程序是在10000个字符里找helloWorld子串)

好了,就介绍这些,附上源码:

 

 

http://emilmatthew.51.net/downloads/kmpTest.rar

 

 

//如果上面这个链接无法响应下载(有可能是被网站给屏蔽掉了),则可使用下载工具(如迅雷等)下载。欢迎提出批评与指正意见

 

 

 

 

你可能感兴趣的:(Algorithm,算法,struct,String,null,下载工具)