算法---字符串匹配
编辑文本时,我们经常需要在文本中找到某串模式字符在整个文本中出现的位置,这个模式字符串即为用户查找输入的关键字,解决这个问题的算法为字符串匹配算法。
当我们遇到这个问题,如何查找在文本中出现的模式呢?
一:朴素字符串匹配
我们假设存在两个游标i,j分别指向文本串与模式串的位置,那么有
1:当匹配到T[i]==P[j],则i++,j++;
2:当在匹配到某一位置时出现T[i]!=P[j]时,即匹配失败,此时i回溯到本次开始匹配的位置,j=0
咱们从代码与匹配图解理解朴素算法思路:
int native_string_matcher(char* T,char* P)
{
//获取原始串和模式串字符长度
int n=strlen(T);
int m=strlen(P);
int s=0,i=0;
//原串开始从0至n-m偏移,以匹配模式串
for(s=0;s<=n-m;s++)
{
//模式串从0-m开始分别匹配模式串中字符是否与原串相等
for(i=0;i<m;i++)
{
if(P[i]!=T[s+i]) //如果在匹配过程中有字符不相等,则跳出该循环,偏移S向下移位,继续重新匹配
{
break;
}
if(i==m-1)//当i=m-1,且P最后字符与T最后字符相等,则表示字符串匹配成功,此时返回原串中与模式串相匹配的起始位置。
printf("has match");
return s;
}
}
}
OK,现在我们举个栗子,
假设有一个文本字符串和模式字符串如下图
(a) 字符串开始匹配,此时T[0]=P[0],i++为1,此时s+i=1,T[1]!=P[1],匹配失败,s自加1,变为1,开始图(b)的匹配过程;
(b) 此时T[s=1]=c!=P[0],匹配失败,s自加1,变为图c的匹配过程
(c) 此刻T[s=2]=P[0],i自加1,T[s+i=3]=P[i=1],字符相等,继续下一匹配,i自加1为2,T[s+i=4]=P[i=2],且此刻i=length(P),匹配结束。此刻,s继续自加,进行余下字符串的匹配。
朴素字符串匹配过程较简单,但是最坏情况下时间复杂度为O((n-m+1)*m),字符串的匹配时间开销较大,并不能很好的解决字符串的匹配。
补充:
在朴素字符串匹配中存在一种特殊情况,即模式串P中的所有字符都不相同,其匹配时间可以达到O(n),具体的实现代码如下:
int native_string_matcher(char* T,char* P)
{
//获取原始串和模式串字符长度
int n=strlen(T);
int m=strlen(P);
int j=0,i;
for(i=0,j=0;i<n;i++)
{
if(T[i]==P[j]&&j<m) ++j;
else{
if(j!=0)
{
j=0;
--i;
}
}
printf("%d\n",i);
if(j==m)
return i-m+1;
}
return -1;//若为-1,代表原始串中不包含模式串
}
这个实现过程很好理解,下面图示匹配过程:
整个匹配流程如下:
(1) 文本串i=0,模式串j=0,此时T[i]!=P[j],匹配失败,i自加1;
(2) 开始匹配,T[1-4]=P[0-3],但T[5]!=P[4],匹配失败,由于P中所有字符互不相同,所以i不必回溯到T[i=2],只需开始匹配T[i-1=4]与P[0]并开始新一轮的匹配过程。
至此,朴素字符串匹配算法结束,整个过程很好理解。