1.模式匹配
模式匹配也被成为暴力匹配,算法的思路在于,从第一个元素开始进行对比当出现不相等的情况,则从第二个元素开始进行对比,以此类推,直到全部匹配完为止。
因为该算法中,主串会需要进行回溯,当元素数量相当多的时候效率是非常低的。我们通过运算时间复杂度也可以看出来。
代码实现(使用C语言,该串运用顺序存储结构)
int StrIndex(SeqString *S1,SeqString *S2,int pos){
int i=pos,j=0;
while(j<S2->len&&i<S1->len){
if(S2->ch[j]==S1->ch[i]){
i++;
j++;
}
else{
j=0;
i=i-j+1;//下一次位置
}
}
if(j==StrLen(S2)){
return i-StrLen(S2);
}else{
return -1;
}
}
2.KMP算法
模式匹配,我们可以知道,当从主串的第一个元素开始匹配出现不匹配情况的时候,要从第二个元素开始向后匹配。
如果我们可以直接找到和前面匹配过相同的元素的位置再向后进行匹配,那主串就不用进行回溯,时间复杂度就可以变为O(m)了。
接下来画个图来描述一下这种思想:
KMP算法是一种改进的模式匹配算法,是由DEKnuth、JHMorris和VRPratt同时发现的,因此成为克努特——莫里斯——普拉特操作(简称KMP算法)
那么如何知道需要向后移动多少个位置?——>next数组
理想状态:
next数组用于匹配
因此对于S1=“abaabcacd”对应的next数组为:next [ ] = {0,1,1,2,2,3,1,2,1}
"abaabcacd"
"abc" (c!=a,向后移动1个位置)
" abc"(a!=b,向后移动1个位置)
" abc"(b!=a,向后移动2个位置)
" abc"(匹配成功)
也就是每次向后移动,都是子串的第next[j]个元素开始进行比较,因为前面的相等无需比较
代码实现:(运用C语言顺序串)
(注意:因为c语言的下标从0开始和上面举的例子有一点差异)
typedef struct{
char ch[MAXSIZE];
int len;
}SeqString;
//KMP算法
int next[100];
void GetNext(SeqString *t,int *next){
int i=0,j=-1;
next[0]=-1;
while(i<t->len){
if(j==-1||t->ch[i]==t->ch[j]){
++i;
++j;
next[i]=j;
}else{
j=next[j];
}
}
}
//t为s的子串,求t在s中的位置索引
int Index(SeqString *s,SeqString *t){
int i=0,j=0;
while(i<s->len&&j<t->len){
if(j==-1||(s->ch[i]==t->ch[j])){
i++;j++;
}else{
j=next[j];//t向右移
}
if(j==t->len)
return i-t->len;
else
return -1;
}
}