一,BF算法
暴力搜索,两重循环,具体略
二,MP算法
与BF算法不同的是,每当匹配失败,不必指针回溯,而是利用已经得到的部分匹配结果,将模式字符串滑动若干位置后,继续比较
当失配的情况发生在模式p的第j位:
1,当j=0,则让目标的指针前进一位,模式的起始比较地址回到P0
2,否则,在进行下一轮比较时,目标指针不发生回溯,仍指向失配的位置,而模式串的起始比较位置为P(f(j-1)+1)
在具体实现上,借助于Next数组,存储的为发生失配时,进行下一轮比较过程中模式p的比较地址
代码:
//p为模式字符串,t为目标字符串
void GetNext(int m){
int i=0,j=-1;
Next[0]=-1;
while(i<m){
while(j>-1&&p[i]!=p[j])
j=Next[j];
Next[++i]=++j;
}
/*Next[m]=0; 不加此句,在目标串匹配出一个,还会考虑模式串前部能否和此时目标串匹配部分的后面继续匹配
加了此句,直接目标串的下一个位置与模式串开头匹配
如ababccde
abab
加了那句,下一步是:
ababccde
abab
不加的话,是:
ababccde
abab */
return;
}
void MP(){
int i=0,j=0;
int n=strlen(t),m=strlen(p);
if(n<m)
return;
GetNext(m);
while(j<n){
while(i>-1&&p[i]!=t[j])
i=Next[i];
i++;
j++;
if(i>=m){
cout<<j-i<<endl;
i=Next[i];
}
}
return;
}
注意:
1:计算Next数组时,字符串前部和后部的匹配部分可能会有重叠
如:abcabcabc
则:abcabcabc
abcabcabc 红色部分匹配
2:注意是要从目标串中能找到多少个模式串(不加注释部分代码),还是能拆分出多少个模式串(加注释部分代码)
三:KMP算法
在MP的基础上,KMP进行了改进:
因为在MP中,P[Next[i]]可能会与P[i]相等,那么其实 还是无法与目标串匹配
在KMP中创建Next数组时,加入了,P[i]不同于P[Next[i]]的条件
代码如下:
void GetNext(int m){
int i=0,j=-1;
Next[0]=-1;
while(i<m){
while(j>-1&&p[i]!=p[j])
j=Next[j];
i++;
j++;
if(p[i]==p[j])
Next[i]=Next[j];
else
Next[i]=j;
}
//Next[m]=0; 作用同上
return;
}
void KMP(){
int i=0,j=0;
int m=strlen(p);
int n=strlen(t);
if(m>n)
return;
GetNext(m);
while(j<n){
while(i>-1&&p[i]!=t[j])
i=Next[i];
i++;
j++;
if(i>=m){
cout<<j-i<<endl;
i=Next[i];
}
}
return;
}
对于:if(p[i]==p[j])
Next[i]=Next[j];
为何不用while循环呢?
这个过程由低到高是逐步进行的,因为Next[i]=Next[j]之前,已经保证了p[j]不等于p[Next[j]],从而现在能保证p[i]不等于p[Next[j]]
MP和KMP的另一种代码形式:
MP:
void GetNext(char p[],int m){
int i=0,j=-1;
Next[0]=-1;
while(i<m){
if(j==-1||p[i]==p[j]){
i++;
j++;
Next[i]=j;
}
else{
j=Next[j];
}
}
//Next[m]=0 作用同上
}
void MP(char s[],char p[]){
int m,n,i=0,j=0;
m=strlen(p);
n=strlen(s);
if(n<m){
return;
}
GetNext(p,m);
while(j<n){
if(i==-1||s[j]==p[i]){
i++;
j++;
if(i>=m){
cout<<j-i<<endl;
i=Next[i];
}
}
else{
i=Next[i];
}
}
}
KMP:
void GetNext(char p[],int m){
int i=0,j=-1;
Next[0]=-1;
while(i<m){
if(j==-1||p[i]==p[j]){
i++;
j++;
if(p[i]==p[j]){
Next[i]=Next[j];
}
else{
Next[i]=j;
}
}
else{
j=Next[j];
}
}
//Next[m]=0 作用同上
}
void KMP(char s[],char p[]){
int m,n,i=0,j=0;
m=strlen(p);
n=strlen(s);
if(n<m){
return;
}
GetNext(p,m);
while(j<n){
if(i==-1||s[j]==p[i]){
i++;
j++;
if(i>=m){
cout<<j-i<<endl;
i=Next[i];
}
}
else{
i=Next[i];
}
}
}