1.BF算法
1.实现代码
#include <iostream>
#include <string>
using namespace std;
// 假设HString类似于std::string
struct HString {
const char* ch; // 将类型更改为 const char*
int len; // 假设你有一个长度属性
};
// BF模式匹配算法
int Index(HString S, int pos, HString T) {
int i = pos; // 主串从pos开始
int j = 1; // 模式串从头开始
while (i <= S.len && j <= T.len) {
if (S.ch[i - 1] == T.ch[j - 1]) { // 当对应字符相等时,比较后续字符
i++;
j++;
} else { // 当对应字符不相等时
i = i - j + 2; // 主串回溯到i-j+2的位置重新比较
j = 1; // 模式串从头开始重新比较
}
}
if (j > T.len) { // 匹配成功时,返回匹配起始位置
return i - T.len;
} else { // 匹配失败,返回0
return 0;
}
}
int main() {
// 假设HString类似于std::string
HString S = { "ababcabcacbab", 13 }; // 根据实际字符串调整长度
HString T = { "abcac", 5 };
int position = Index(S, 1, T); // 从位置1开始搜索
if (position != 0) {
cout << "Pattern found at position: " << position << endl;
} else {
cout << "Pattern not found." << endl;
}
return 0;
}
注意到修正的地方:
- 在数组中,索引是从0开始的,因此在比较字符时,使用
S.ch[i - 1]
和T.ch[j - 1]
来访问数组元素。看自己需要,有些直接舍弃一个空间,从1开始算。 - 在返回匹配位置时,使用
i - T.len
而不是i - T.len + 1
,因为索引是从1开始的。
BF算法(朴素字符串匹配算法)是计算机科学中最经典的字符串匹配算法之一。它的主要思想是通过不断地比较目标字符串和模式字符串的字符来寻找匹配的位置。
BF算法的主要知识点:
- 算法思想:BF算法的思想很简单,就是从目标字符串的第一个字符开始,逐个比较它和模式字符串的字符是否匹配。如果匹配,则继续比较后面的字符;如果不匹配,则将模式字符串向右移动一位,然后重新开始比较。
- 算法流程:BF算法的流程如下:
a. 初始化两个指针i和j,分别指向目标字符串和模式字符串的第一个字符。
b. 在循环中,比较目标字符串的第i个字符和模式字符串的第j个字符是否相等。如果相等,则将i和j都加1,继续比较后面的字符。
c. 如果不相等,则将模式字符串向右移动一位(即将j重置为0),然后将i加1,重新开始比较。
d. 如果目标字符串被完全扫描完毕(即i等于目标字符串的长度),而模式字符串还没有完全匹配(即j小于模式字符串的长度),则说明模式字符串不存在于目标字符串中,返回-1表示匹配失败。
3. 时间复杂度:BF算法的时间复杂度是O(mn),其中m和n分别是目标字符串和模式字符串的长度。在最坏的情况下,BF算法需要比较mn次。
- 空间复杂度:BF算法的空间复杂度是O(1),因为它只需要常数级别的额外空间来存储比较过程中的临时变量。
- 优化:虽然BF算法很基础,但是在某些情况下可以通过一些技巧来提高它的效率。例如,可以使用坏字符规则来跳过一些不可能存在匹配的位置,从而减少比较次数。此外,也可以使用好后缀规则来加速匹配过程。
总之,BF算法是一种简单而有效的字符串匹配算法,适用于各种应用场景。了解并掌握BF算法可以帮助你更好地理解字符串匹配问题的解决方法。
2.KMP
int index_KMP(SString S,SString T, int pos)
{
i = pos;
j = 1;
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;
}
KMF算法的设计思想主要是为了在匹配字符串时,遇到失败的情况时尽最大可能的利用失败信息,以防从头开始匹配。它是一种改进的KMP算法,在KMP算法的基础上引入了next数组。KMF算法的next数组的设计与构造与KMP算法中的相同,都是通过自底向上的方式来构造。
在KMF算法中,一旦当前匹配失败,就可以通过查找上一个匹配成功应该回退的位置来避免从头开始匹配。这个位置就是KMF算法中的next数组所表示的。通过next数组,可以将当前位置的失败状态转移到上一个匹配成功的位置,从而避免重复匹配。
如图,i = 8时发现与j = 6不匹配,根据next[j]发现有next[j] - 1个和开头一样的,可以起到避免重复比较的效果
next[j]算法:
:
void get_next(SString T,int next[])
{
i=1;j=0;
next[1]=0;
while(i<T.length)
{
if(j==0||T.ch[i] ==T.ch[j])
{
++i;
++j;
next[i]=j;
}
else j = next[j];
}
}
nextval:
void Get_Next(HString T, int next[]) {
int j = 1, k = 0;
next[1] = 0;
while (j < T.len) {
if (k == 0 || T.ch[j] == T.ch[k]) {
++j;
++k;
next[j] = k;
}
else {
k = next[k];
}
}
}
void Get_NextVal(HString T, int next[], int nextval[]) {
int j = 2, k = 0;
Get_Next(T, next);
nextval[1] = 0;
while (j <= T.len) {
k = next[j];
if (T.ch[j] == T.ch[k]) {
nextval[j] = nextval[k];
}
else {
nextval[j] = next[j];
}
j++;
}
}