数据结构---串的模式匹配算法
串的模式匹配算法
BF算法
算法思想:
指定主串中查找的起始位置pos,主串字符和模式串字符一一比较,遇到不相等则回溯到主串的下一个位置,模式串的第一个位置进行比较,直到分别对应相等则匹配成功
算法步骤:
-
指针i和j指示主串 S 和模式 串T中当前正待比较的字符位置, i初值为pos,j初值为1。
-
如果两个串均未比较到串尾, 即i和j均分别小于等于S和T的长度时,则循环执行以下操作:
- S[i].ch和T[j].ch比较,若相等,则i和j分别指示串中下个位置, 继续比较后续字符;
- 若不等,指针后退重新开始匹配, 从主串的下一个字符 (i=i-j+2) 起再重新和模式的第一个字符 (j=i) 比较。
-
如果j> T.length, 说明模式T中的每个字符依次和主串S中的一个连续的字符序列相等,则匹配成功,返回和模式T中第一个字符相等的字符在主串S中的序号(i-T.length); 否则称匹配不成功,返回0。
代码实现:
int Index(SString* S, SString* T, int pos)//朴素的模式匹配算法
{
if (pos<1 || pos>S->length)//保证输入起始位置正确
{
cout << "输入有误!请重新输入" << endl;
return 0;
}
int i = pos;//初始化
int j = 1;
while (i <= S->length && j <= T->length)//两个串都没有比较到串尾
{
if (S->ch[i] == T->ch[j])//相等,继续比较后继字符
{
++i;
++j;
}
else//否则,i返回到原来起始位置的下一位置,j返回到第一个字符位置
{
i = i - j + 2;
j = 1;
}
}
if (j > T->length)//j到了最后一个字符的下一位置
return i - T->length;//返回匹配成功T在S中第一个字符的位置
else
return 0;
}
分析:设主串的长度为n, 子串的长度为m
最坏的情况,在最后一趟比较中匹配成功,最后一趟为第(n-m+1)趟,一共进行了(n-m+1)趟比较,每一趟比较的次数为m,所以总次数为(n-m)*m
最好的情况,在第一趟比较中就匹配成功,比较的次数为m
综合得到平均时间复杂度为O(m*n)
KMP算法
算法思想:
每当一趟匹配过程中出现字符比较不等时,不需回溯i指针,而是利用已经得到的 ”部分匹配" 的结果将模式串向右“滑动“ 尽可能远的一段距离后,继续进行比较。
这里和BF算法的主要区别就是没有回溯i指针,j指针不需要再从1开始,而是从next[j]开始
简便记法:
next[j]的值--->在j上出现不匹配的字符位置之前的所有字符前缀和后缀相同的最大个数+1
并且当指针j 退至零时,指针i和指针 j需同时增 1,即若主串的第i个字符和模式的第1 个字符不等,
应从主串的第i+1个字符起重新进行匹配。
计算next函数值
void get_next(SString* T, int* next)//求模式串 T的 next 函数值并存入数组 next
{
int i, j;
i = 1;
j = 0;
next[1] = 0;
while (i < T->length)
{
if (j == 0 || T->ch[i - j] == T->ch[j])
{
++i;
++j;
next[i] = j;
}
else
j = next[j];
}
}
代码实现
int Index_KPM(SString* S, SString* T, int pos)//KPM模式的串的匹配算法
{
int i = pos;
int j = 1;
int next[255];
get_next(T, next);
while (i <= S->length && j <= T->length)//保证两个串均没有比较到串尾
{
if (j == 0 || S->ch[i] == T->ch[j])//继续比较后继字符
{
++i;
++j;
}
else
{
j = next[j];
}
}
if (j > T->length)
return i - T->length;
else
return 0;
}