字符串匹配算法
1、字符串相关的算法很多,今天总结的是字符串匹配算法,之前已知的有两种算法,一种叫做BF(Brute Force)算法,也就是蛮力算法,就是匹配串和模式串左对齐,不匹配则模式串向右移一个单位,直到匹配或结束,这中间有很多无用的匹配,特别是对匹配串中有重复字符串出现的时候;第二种就是第一种方法的改进,叫做KMP算法,此算法晦涩难懂,但归根结底就两句话,一是找出匹配串的next数组,二是不匹配时的移动规则。BF算法比较简单,此不详述,下面给出了KMP算法,已在VS2005上调试通过。
//Contact是一个类——联系人,匹配的是电话号码
void KMP(Contact &c, string partStr)
{
if (partStr.length() <= 0)
return;
int * next = new int[partStr.length()];
if (NULL == next)
return;
findNext(next, partStr);
string tmpStr = partStr;
unsigned int str_i=0;
for (unsigned int phone_i=0; phone_i < c.getPhone().length() && str_i < tmpStr.length(); )
{
if (c.getPhone()[phone_i] != tmpStr[str_i])
{
if (next[str_i] >= 0)
{
str_i = next[str_i];
}
else if (-1 == next[str_i])
{
str_i = 0;
++phone_i;
}
}
else
{
++phone_i;
++str_i;
}
}
if (str_i == tmpStr.length())
cout<<c.getName()<<" "<<c.getPhone()<<endl;
}
//对于匹配串每个元素对应的next数组中的值是其前面字符串前缀等于后缀的最大长度。
//如“ababcd”,字符’c’的next数组对应的值大小为2.
void findNext(int next[], string partStr)
{
if(NULL == next || partStr.length() <= 0)
return;
for(unsigned int i = 0; i < partStr.length(); ++i)
{
if(0 == i)
next[i] = -1;
else if(1 == i)
next[i] = 0;
else
{
for(unsigned int back = 1; back < i; ++back)
{
unsigned int front = 0, count=0, tmpBack = back;
next[i] = 0;
while(partStr[front] == partStr[tmpBack] && tmpBack < i)
{
++front;
++tmpBack;
++count;
}
if(tmpBack == i)
{
next[i] = count;
break;
}
}
}
}
在这里引申一下,前几天在一家国内著名互联网公司的笔试中出现了一道次方法的变种,如果不匹配,则要找到最大可匹配的长度,在这里只简单说下思想,比如模式串为“abcde”,如果没有完全匹配的,可记下最大匹配长度,注意这里是从首字符开始匹配的,也就是任意长度可匹配的字符串均从首字符开始,如最大为3,则是“abc”;然后模式串变为“bcde”,此时还需要重新算next数组,再次匹配,也是从首字符开始匹配的,也就是任意长度可匹配的字符串均从首字符开始,如最大为3,则是“bcd”;依次下去,找到最大的可匹配长度。
3、下面介绍一种更高效的算法:Sunday算法。Sunday算法是Daniel M.Sunday于1990年提出的字符串模式匹配。其核心思想是:在匹配过程中,模式串发现不匹配时,算法能跳过尽可能多的字符以进行下一步的匹配,从而提高了匹配效率。
如匹配串“stay student studying”、模式串“study”,如下图,第一个第二个匹配,第三个不匹配,那么匹配串中哪个字符一定会在下次匹配中出现呢,是模式串末尾’y’对应’s’后面的’t’,此时我们需要寻找’t’在模式串中是否出现,结果模式串中存在’t’,相匹配。
stay student studying
study
我们发现在最后一个字符不匹配,e-y不匹配,此时需要找’n’是否在study出现,结果没有,继续往后,’t’出现了,相匹配。
stay student studying
study
我们发现首字符不匹配,s-n不匹配,此时需要找’d’是否出现在模式串中,找到了。
stay student studying
study
将’d’对齐,我们此时便找到了匹配的字符串,是不是很快。
stay student studying
study