2.Sunday算法
Sunday算法与KMP算法一样是从前往后匹配,在匹配失败时关注的是主串中参加匹配的最末位的下一位字符。
如果该字符没有在模式串中出现则直接跳过,即移动位数=模式串长度+1;
否则,其移动位数=模式串长度-该字符最右出现的位置(从0开始)=模式串中该字符最右出现的位置到尾部的距离+1
例:假定现在要在主串substring searching xiaowu中查找search。
1.刚开始时,把模式串与文本串左边对齐:
2.结果发现在第2个字符处发现不匹配,不匹配时关注文本串中参加匹配的最末位字符的下一位字符,即绿色的字符i,因为模式串search中并不存在i,所以模式串直接跳过一大片,向右移动位数=匹配串长度+1=6+1=7,从i之后的那个字符(即字符n)开始下一步的匹配。
3.结果第一个字符就不匹配,在看文本串中参加匹配的最末位字符的下一位字符,是“r”,他出现在模式串中的倒数第3位,于是把模式串向右移动3位(r到模式末尾的距离+1=2+1=3),使两个“r”对齐。
4.匹配成功
整个过程,我们只移动了两次就找到了匹配的位置,是因为Sunday算法的每一步移动量都比较大,效率很高。
代码:
#include <iostream>
#include <string>
using namespace std;
const int maxNum = 1005;
int shift[maxNum];
int Sunday(const string& T, const string& P) {
int n = T.length();
int m = P.length();
// 默认值,移动m+1位
for (int i = 0; i < maxNum; i++) {
shift[i] = m + 1;
}
// 模式串P中每个字母出现的最后的下标
// 所对应的主串参与匹配的最末位字符的下一位字符移动到该位,所需要的移动位数
for (int i = 0; i < m; i++) {
shift[P[i]] = m - i;
}
// 模式串开始位置在主串的哪里
int s = 0;
// 模式串已经匹配到的位置
int j;
while (s <= n - m) {
j = 0;
while (T[s + j] == P[j]) {
j++;
// 匹配成功
if (j >= m) {
return s;
}
}
// 找到主串中当前跟模式串匹配的最末字符的下一个字符
// 在模式串中出现最后的位置
// 所需要从(模式串末尾+1)移动到该位置的步数
s += shift[T[s + m]];
}
return -1;
}
/**
IN
at the thought of
though
OUT
7
**/
int main() {
// 主串和模式串
string T, P;
while (true) {
// 获取一行
getline(cin, T);
getline(cin, P);
int res = Sunday(T, P);
if (res == -1) {
cout << "主串和模式串不匹配。" << endl;
}
else {
cout << "模式串在主串的位置为:" << res+1 << endl;
}
}
return 0;
}