串是内容受限的线性表
由于平时更多使用匹配、查找运算,所以更多使用顺序存储结构的串。
下面主要学串的模式匹配算法,有两大算法:BF算法、KMP算法;
KMP算法流程以及next数组构建:
对于 next数组如何构建:下标j之前的最长公共前后缀长度 + 1;
#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#define MAXLEN 100
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
// 串的定义
//typedef struct SString
//{
// char ch[MAXLEN]; // 存储串的数组
// int length; // 串的当前长度
//};
int GetSlen(string S)
{
int Slen = S.size();
return Slen;
}
int GetTlen(string T)
{
int Tlen = T.size();
return Tlen;
}
int Index_BF(string S, string T, int pos)
{
int i = pos, j = 1;
int Slen = S.size();
int Tlen = T.size();
while (i <= Slen && j <= Tlen) // 判断条件:用来保证匹配到或者没匹配到都能跳出循环
{
if (S[i] == T[j]) // 主串与子串依次匹配下一个
{
++i;
++j;
}
else // 遇到不匹配的直接回溯,并与主串下一个元素开始匹配
{
i = i - j + 2; // 主串的下表 i 去到下一个元素
j = 1; // 子串的下表 j 开始回溯
}
}
if (j > Tlen) // 子串的下表 j 超出子串长度了,说明找到了,并且这里只能写大于>,因为while的 ++j作用
{
cout << "BF算法匹配成功!" << endl;
return i - Tlen; // 返回匹配的第一个字符的下标;用 i 减去 移动的距离,即返回了第一个元素在主串中的坐标
}
else
{
return 0;
}
}
// 下面是 KMP 算法:
// next 数组的构建:子串的下标 j 之前的最长公共前后缀长度 + 1
void get_next(string T,int next[]) // int next[]
{
int i = 1, j = 0; // 这里 i和j 都在子串T中,j在i前一个位置;
int Tlen = T.size();
next[1] = 0; // 第一个位置的 next 必为 0
while (i < Tlen)
{
if (j == 0 || T[i] == T[j])
{
++i;
++j;
next[i] = j;
}
else // 这部分看 b站视频:凡三岁爱学习讲解
{
j = next[j];
}
}
}
//
int Index_KMP(string S, string T, int pos)
{
int i = pos, j = 1;
int Slen = S.size();
int Tlen = T.size();
int next[10];
get_next(T, next);
while (i <= Slen && j <= Tlen)
{
if (j == 0 || S[i] == T[j])
{
++i;
++j;
}
else
{
j = next[j];
}
}
if (j > Tlen)
{
cout << "KMP算法匹配成功!" << endl;
return i - Tlen;
}
else
{
return 0;
}
}
int main()
{
/*SString S = "abababaababbaa";
SString T = "abbba";*/
string S = "abaababbbbaa";
string T = "bbaa";
cout << GetSlen(S) << endl;
cout << GetTlen(T) << endl;
cout << " " << endl;
int index = Index_BF(S, T, 1);
cout << "BF算法:" << index << endl;
cout << " " << endl;
index = Index_KMP(S, T, 1);
cout << "KMP算法:" << index << endl;
return 0;
}