(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中的求解结果。至于第一个字符,由于没有“上一个字符”的说法,直接设置为-1,即可。
看一个具体的例子:
模式串 "ababca"
最长前后缀长度表
第4位B:子串abab,前缀a,
ab
,aba 后缀 b,
ab
,bab 等于2
模式串 | a | b | a | b | c | a |
最长前后缀长度 | 0 | 0 | 1 | 2 | 0 | 1 |
由上表得出next数组
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
next | -1 | 0 | 0 | 1 | 2 | 0 |
直观地看就是:把“最长前后缀长度表”右移一个位置,于是最右边的一个长度被丢弃掉了,最左边空出的填上-1。这样得到的就是next数组。
当模式串的长度很小的时候,手动计算next数组也没什么问题。可手动计算终究不是办法,必须机器计算。实际上next数组可以递推求解,这也是一个理解上的难点。
(i)初始 next[0]=-1;
(ii)若next[j]为k,即有 P0...Pk-1(Pk...)=Pj-k...Pj-1(Pj...)(*式)('='的意义:对应位置相匹配)。分两种情况,求解next[j+1]:
- if(Pk==Pj),则 next[j+1]=k+1=next[j]+1; 道理显而易见:若Pk与Pj相等,则最长前后缀顺势增长一个,由*式可以看出。
- 若Pk与Pj不相等,则更新 k=next[k];if(Pk==Pj) next[j+1]=k+1;否则,重复此过程。(这里也是个匹配问题)
- /*
- 根据模式串P,设置next数组的值
- */
- void setNext(const char* P, int* next)
- {
- int j, k, lenP;
- lenP = strlen(P);
- j = 1;
- next[0] = -1;
- while (j < lenP) //活动指针,保证不越界
- {
- if(k==-1||ch[j]==ch[k]){ //新比较的相等了,指针后移,k++; 并复制
- j++;k++;
- next[j]=k;}
- else
- k = next[k]; //不等的话,重新开始k值
- }
- }
- /*
- 串的模式匹配:KMP算法
- (i)T是主串,其形式是字符串常量或者是以'\0'结尾的字符串数组,如"abc"或{'a','b','c','\0'}
- (i)P是子串,其形式和主串一样
- (i)next数组
- (o)匹配成功,返回主串中第一次匹配成功的下标;否则,返回-1
- */
- int KMP(const char *T, const char *P, const int *next)
- {
- if (T && P)
- {
- //lenT是主串长度,lenP是子串长度
- int lenT, lenP;
- lenT = strlen(T), lenP = strlen(P);
- //主串长度小于子串,显然无法匹配
- if (lenT < lenP)
- return -1;
- int i, j, pos;
- i = j = -1;
- pos = lenT - lenP; //i最多只需变化到pos位置,想想?很简单的
- while (i <= pos && j < lenP) //活动指针,保证不越界
- {
- //匹配成功或第一次匹配
- if (j == -1 || T[i] == P[j]) //新比较的相等了,指针后移,k++;
- {
- i++;
- j++;
- }
- else//匹配失败 //不等的话,跳跃
- j = next[j];
- }
- if (j == lenP)
- return i - lenP; //这个返回值很好理解
- else
- return -1;
- }
- return -1;
- }
给定一主串 "cadabababcacadda",模式串 "ababca",next数组同上:next[]={-1,0,0,1,2,0}