(1.2.3)串的结构定义和模式匹配

 

(1)顺序串的结构定义

typedef struct{

char ch[maxsize];

int length;

}seqstring;

(2) 零个字符的串为空串;一到多个空格组成的串为空格串。

   s='a1a2a3a4a5a6a7a8a9'

   s为 a1 a2 a3 a4 a5 a6 a7 a8 a9 \0    占据1位

    但是s的长度为9

 

(3)动态串的结构定义

   typedet struct {

char *ch;

int length;

}seqstring

 

(4)朴素模式匹配:O(M*N)

把模式串跟母串从左向右或从右向左一点一点比较:先把模式串的第一个字符同母串的第一个字符比较,若相等则接着比较后面的对应字符;若不等,把模式串后移一个位置,再次从模式串的头部比较……这如同枚举法:把母串中与模式串相同长度的子串挨个比较。



 

int find(char *&path,char *&ch, int k)//从母串k出开始匹配子串ch

{

for(i=k;i<=length-ch.length;++i){

 

for(j=0;j<ch.length;++j)

if(path[i+j]!=ch[j]) break;//一个不等推出循环

if(j=ch.length) return i;//子串长度全部匹配

}

return -1;

}

(5)KMP:O(M+N)

模式匹配。每次出现失败,就从主串长度向下移动1个位置。
kmp,向下移动 j-next[j]>=1
 
 

Next数组完全由模式串本身确定,与主串无关!:从冲突位向前看的,可重复位数

求解next数组的步骤

  1. 先求出以当前字符结尾的子串 的 最长相对应前缀和后缀的长度。
  2. 当前字符的next值,需要参考(参考就是取的意思)上一个字符的步骤1中的求解结果。至于第一个字符,由于没有“上一个字符”的说法,直接设置为-1,即可。
看一个具体的例子:
模式串 "ababca"
最长前后缀长度表
第4位B:子串abab,前缀a, ab ,aba  后缀 b, ab ,bab  等于2
模式串ababca
最长前后缀长度001201
由上表得出next数组
下标012345
next-100120
 
直观地看就是:把“最长前后缀长度表”右移一个位置,于是最右边的一个长度被丢弃掉了,最左边空出的填上-1。这样得到的就是next数组。
 

next数组的递推求解

 
当模式串的长度很小的时候,手动计算next数组也没什么问题。可手动计算终究不是办法,必须机器计算。实际上next数组可以递推求解,这也是一个理解上的难点。
(i)初始 next[0]=-1;
(ii)若next[j]为k,即有 P0...Pk-1(Pk...)=Pj-k...Pj-1(Pj...)(*式)('='的意义:对应位置相匹配)。分两种情况,求解next[j+1]:
  1. if(Pk==Pj),则 next[j+1]=k+1=next[j]+1; 道理显而易见:若Pk与Pj相等,则最长前后缀顺势增长一个,由*式可以看出。
  2. 若Pk与Pj不相等,则更新 k=next[k];if(Pk==Pj) next[j+1]=k+1;否则,重复此过程。(这里也是个匹配问题)
 
  1. /* 
  2. 根据模式串P,设置next数组的值 
  3. */  
  4. void setNext(const char* P, int* next)  
  5. {  
  6.     int j, k, lenP;  
  7.     lenP = strlen(P);  
  8.     j = 1;  
  9.     next[0] = -1;  
  10.     while (j < lenP)          //活动指针,保证不越界
  11.     {  
  12.      if(k==-1||ch[j]==ch[k]){ //新比较的相等了,指针后移,k++;  并复制 
  13.         j++;k++;
  14.         next[j]=k;}
  15.       else 
  16.          k = next[k];            //不等的话,重新开始k值
  17.     }  
  18. }  
  19. /* 
  20. 串的模式匹配:KMP算法 
  21. (i)T是主串,其形式是字符串常量或者是以'\0'结尾的字符串数组,如"abc"或{'a','b','c','\0'} 
  22. (i)P是子串,其形式和主串一样 
  23. (i)next数组 
  24. (o)匹配成功,返回主串中第一次匹配成功的下标;否则,返回-1 
  25. */  
  26. int KMP(const char *T, const char *P, const int *next)  
  27. {  
  28.     if (T && P)  
  29.     {  
  30.         //lenT是主串长度,lenP是子串长度  
  31.         int lenT, lenP;  
  32.         lenT = strlen(T), lenP = strlen(P);  
  33.         //主串长度小于子串,显然无法匹配  
  34.         if (lenT < lenP)  
  35.             return -1;  
  36.         int i, j, pos;  
  37.         i = j = -1;  
  38.         pos = lenT - lenP;  //i最多只需变化到pos位置,想想?很简单的  
  39.         while (i <= pos && j < lenP)      //活动指针,保证不越界
  40.         {  
  41.             //匹配成功或第一次匹配  
  42.             if (j == -1 || T[i] == P[j])  //新比较的相等了,指针后移,k++; 
  43.             {  
  44.                 i++;  
  45.                 j++;  
  46.             }  
  47.             else//匹配失败                 //不等的话,跳跃
  48.                 j = next[j];  
  49.         }  
  50.         if (j == lenP)  
  51.             return i - lenP;  //这个返回值很好理解  
  52.         else  
  53.             return -1;  
  54.     }  
  55.     return -1;  
  56. }  
  57.  
给定一主串 "cadabababcacadda",模式串 "ababca",next数组同上:next[]={-1,0,0,1,2,0}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值