目标串:s(从该字符串中查找)
模式串:t(需要从s中匹配的字符串)
1.BF算法:
采用穷举法,分别从s串的第一个字符开始与t串进行匹配,若相同则分别加1,不相同则s串进一格,t串回到开头再次与s串进行比较。
int BF(string t, string s)
{
int i = 0, j = 0; //i,j分别作为t,s上的游标
while (i < t.length() && j < s.length())
{
if (t[i] == s[j])
{
i++;
j++;
}
else
{
j = j - i + 1; //j回到s串中下一个字符
i = 0;
}
}
if (i == t.length())
{
return j - i;
}
else
{
return -1;
}
}
BF算法比较简单易懂,但是效率不高。假设s串有m个字符,t串有n个字符
最坏时间复杂度(mn)
平均时间复杂度(mn)
2.KMP算法
考虑到BF算法的缺点KMP算法充分的利用了之前匹配完成的信息,从而加了匹配速度。
原理:
引入子串的概念对模式串t进行分析。若该字串t具有某种规律,即可利用之前已经和s串匹配好的信息,从而省去s串回溯的过程。若t串的第t[j]具有性质t[1]t[2]=t[j-2]t[j-1]那么根据之前已经匹配好的信息可知t[1]t[2]处的字符串与s串中与t[j-2]t[j-1]相匹配的字符完全相同,那么我们就可以省去s的回溯并直接将t[3]与s上游标所指的字符进行比较。
这样可以将已经适配好的字符串看做是t串的一部分,此时根据next数组的算法可知当且仅当t头子串和s尾子串匹配时这一种情况符合,否则t串不可能与s串匹配。
int BF(string t, string s)
{
int i = 0, j = 0; //i,j分别作为t,s上的游标
while (i < t.length() && j < s.length())
{
if (t[i] == s[j])
{
i++;
j++;
}
else
{
j = j - i + 1;
i = 0;
}
}
if (i == t.length())
{
return j - i;
}
else
{
return -1;
}
}
int FindNext(string t,int* next) //寻找next数组方法1
int index = 0;
int i = -1;
int j = 0;
while (index < t.length())
{
if (index == 0)
{
next[index] = 0;
index++;
}
if (i==-1 ||t[i] == t[j])
{
i++;
j++;
next[index] = i;
index++;
}
else
{
i = 0;
while (t[i] == t[j])
{
j--;
}
while (j < index)
{
if (t[i] == t[j])
{
i++;
j++;
}
else
{
i = 0;
j++;
}
}
next[index] = i;
index++;
}
}
return 0;
}
int KMPNext(string t,int* next) //KMP算法中寻找next数组的方法
{
int i = 0; //t串索引,不发生回退
int j = -1; //记录相同元素个数
next[0] = -1;
while (i < t.length())
{
if (j == -1 || t[i] == t[j])
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j]; //利用之前得到的加速匹配信息来减少回退
}
}
return 0;
}
int KMP(string t, string s)
{
int i=0; //s串游标
int k = -1; //匹配成功字符个数
int next[20];
KMPNext(t, next);
while (k<(int)t.length())
{
if (k == -1 || t[k] == s[i])
{
k++;
i++;
}
else
{
k = next[k];
}
}
if (k == t.length())
{
return i - k;
}
else
{
return -1;
}
}
//测试代码
int main()
{
int Next[20];
int next[20];
int k = 0;
int s = 0;
k=BF("aaab", "aaaaaabcaaab");
s = KMP("aaab", "aaaaaabcaaab");
cout << k;
FindNext("aaabaacaaadyaccaaabm", Next);
KMPNext("aaabaacaaadyaccaaabm", next);
for (int i = 0; i < 20; i++)
{
cout << " " << Next[i];
cout << " " << next[i];
}
return 0;
}