朴素模式匹配算法
- 算法描述:定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0。
- 算法思想:就是把比較主串字符串一位一位地跟模式字符串相比,比较简单粗暴。
- 算法缺点:当某些子串与模式串能部分匹配时,主串的扫描指针 i 经常回溯,导致时间开销增加
//朴素匹配算法
int SimpleIndex(String S,String T)
{
int result=-1;
int i=1,j=1,k=1;
while(i<S.length&&j<T.length)
{
if(S.data[i]==T.data[j])
{
i++;
j++;
}
else
{
k++;
i=k;
j=1;
}
}
if(j>=T.length) //如果找到,则输出找到位置
result=k;
return result;
}
测试代码
String S,T;
InitString(&S);
InitString(&T);
StrAssign(&S,"wangdao");
printf("输出比较字符串S:");
PrintString(S);
StrAssign(&T,"dao");
printf("输出模式字符串T:");
PrintString(T);
int result=SimpleIndex(S,T);
printf("SimpleIndex(S,T):%d\n",result);
return 0;
测试结果
输出比较字符串S:wangdao
输出模式字符串T:dao
SimpleIndex(S,T):5
KMP算法
- 算法描述:由D.E.Knuth,J.H.Morris和V.R.Pratt提出,因此称为 KMP算法。在朴素匹配算法的基础上,为了减少主串指针I的回溯。
- 算法代码:
//KMP算法
int Index_KMP(String S,String T,int next[])
{
int i=1,j=1;
while(i<S.length&&j<T.length)
{
int s_value=S.data[i];
int t_value=T.data[j];
if(j==0||s_value==t_value)
{
i++;
j++;
}
else
{
j=next[j];
}
}
if(j>=T.length)
return i-T.length;
else
return -1;
}
求模式串的Next数组
void GetKMP_NextArr(String S,int next[])
{
next[1]=0;
int j=0,i=1;
while(i<S.length)
{
if(j==0||S.data[i]==S.data[j])
{
i++;j++;
next[i]=j;
//printf("next[%d]=%d\n",i,j);
}else
{
//printf("%d=next[%d]\n",next[j],j);
j=next[j];
}
}
}
测试代码
String S,T,V;
InitString(&S);
InitString(&T);
StrAssign(&S,"aaaacaaaabeccdd");
StrAssign(&T,"aaaab");
int next[6];
GetKMP_NextArr(T,next);
PrintNextArr(next,6);
int result_index=Index_KMP(S,T,next);
printf("Index_KMP(S,T,next)=%d\n",result_index);
测试结果
---next数组输出开始----
0 1 2 3 4
---next数组输出结束----
原字符串:aaaacaaaabeccdd
匹配字符串:aaaab
Index_KMP(S,T,next)=5
Press any key to continue
KMP算法优化
KMP在朴素算法上的改进已经优化了主字符串回溯的问题,但是对于已知匹配字符串的情况下,可以对字符串的索引提前预判,从而达到性能更优的效果。
其实一般情况下,nextval数组和next数组是相等的。但是在极端的情况下,nextval可以比next少对比几次,从而提升执行效率。如以下情况:
index | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
匹配字符串 | a | a | a | a | b |
next | 0 | 1 | 2 | 3 | 4 |
nextval | 0 | 0 | 0 | 0 | 4 |
以上这种情况可以少对比4次,可以这样理解:nextval优化的方法主要针对匹配字符串的重复元素的无意义对比。
求模式串的NextVal数组
void GetKMP_NextValArr(String S,int nextval[])
{
nextval[1]=0;
int j=0,i=1;
while(i<S.length)
{
if(j==0||S.data[i]==S.data[j])
{
i++;j++;
if(S.data[i]!=S.data[j])
nextval[i]=j;
else
nextval[i]=nextval[j];
}else
{
j=nextval[j];
}
}
}
测试代码
String S,T;
InitString(&S);
InitString(&T);
StrAssign(&S,"aaaacaaaabeccdd");
StrAssign(&T,"aaaab");
int next[6];
GetKMP_NextValArr(T,next);
int result_index=Index_KMP(S,T,next);
printf("Index_KMP(S,T,next)=%d\n",result_index);
测试结果
Index_KMP(S,T,next)=5