数据结构 — 查找IV

来源:互联网 发布:无网络小游戏 编辑:程序博客网 时间:2024/05/03 11:44

字符串模式匹配

 

定义】是求第一个字符串(模式串 )在第二个字符串(主串)中的位置。

 

一.简单模式匹配算法

 

【算法描述】 从主串S指定字符开始(一般为第一个)和模式串T的第1个字符比较,若相等,则继续逐个比较后续字符,直到T中的每个字符依次和S中的一个连续字符序列相等,则称匹配成功;如果比较过程中有某对字符不相等,则从主串S的下一个字符再重新和T的第一个字符比较如果S中的字符都比完了仍然没有匹配成功,则称匹配不成功。

        

         【伪代码】

         Intindex(Sstring S,Sstring T)

{

Int i=1,j=1;

While(i<s[0]&&j<T[0])

{

         If(S[i]==T[i])

         {

++i;

++j;
}

                            Else

                            {

                                     I=i-j+2;

                                     J=1;

                            }

}

If(j>T[0])                               //表示T中字符被逐个比较完毕

Return i-T[0];

}



一. KMP算法

 

【改进】每当一趟匹配过程中出现字符不等时,不需回溯i指针,而是利用已得到的“部分匹配”的结果将模式串向右”滑动“ 尽可能远的一段距离后继续进行比较。

 

假设原始串为S,长度为n,模式串为T,长度为m.目前匹配到如下位置。







假设长度为j-1的S串对应结果已经求出,即next[ j-1 ]的函数值k已经求出,现在要求next[j]的函数值,由于 1~k-1的子串与j-k~j-1的子串是匹配的。下面需分两种情况讨论:

1.        模式串下标k处的字符与j-1处字符匹配,即1~k位置的子串与j-k~j-1位置的子串匹配,则next[j]=k+1,即next[j]=next[j-1]+1

2.        模式串下标k处字符与j-1处不匹配,此时我们要做的是等效于向前移动S2串,消除j-1处的不匹配,移动到哪个位置合适呢?显然是next[k]。因为这其实又是一次模式串匹配的问题,假设next[ k ]=k’ (next[k]表示当模式串匹配到T[k]遇到失败时,在模式串中需要重新和主串匹配的位置),相当于找到了S串中这么一对子串 1~k’-1和 j-1-(k’+1)~j-1是匹配的, 回到1,否则回到2

         3)将S[j-1]与S[k]进行比较:

                   a.如果相等,则该next[j]=k+1

                   b.如果不等,令k=next[k],若k不等于0,跳到3;若k等于0,next[j]=1(1表示模式串第一个字符

 

【普通版】

void get_next(char T[],int next[])

{

         inti=1;

         next[1]=0;                  //next[1]初始化,next数组定义的

         intj=0;

         while(i<=T[0])

         {

                   if(j==0||T[i]==T[j])     //j=0情况是模式串需重新开始比对

                   {

                            ++i;

                            ++j;

                            next[i]=j;

                   }

                   else

                            j=next[j];

         }

}

 

【增强版】

void get_nextval(char T[],int next[])

{

         inti=1;

         next[1]=0;

         intj=0;

         while(i<=T[0]-'0')

         {

                   if(j==0||T[i]==T[j])

                   {

                            ++i;

                            ++j;

                            if(T[i]!=T[j])                //避免子串中重复出现一系列字符

                                     next[i]=j;

                            else

                                     next[i]=next[j];

                   }

                   else

                            j=next[j];

         }

}

 

int KMP(char S[],char T[],int next[],intpos)

{

         //利用模式串T的next函数求T在主串S第pos个字符之后的位置

         //其中T[]非空,1<=pos<strlen(S)

         inti=pos;

         intj=1;

         while(i<=S[0]&&j<=T[0])

         {

                   if(j==0||S[i]==T[j])    //j=0情况是模式串重新回到了第一个字符的位置

                   {

                            ++i;

                            ++j;

                   }

                   else

                            j=next[j];

         }

         if(j>T[0])

                   returni-T[0];

         else

                   return0;

}

 

 

【小结】尽管简单模式匹配算法时间复杂度为O(n*m),kMP时间复杂度为O(m+n),但在一般情况下,简单模式实际时间执行近似O(n+m),因此至今仍被采用。KMP算法,仅仅是在主串和子串有很多部分匹配时,才显得快很多,主要优点是主串不回溯。



0 0