出于对期末的数据结构复习,我写下我自己的一些见解和认识。首先出于对我自己的要求,我对自己的代码力求简洁明了,并且会在难懂的地方注释。
串匹配:BF匹配过程及实现、KMP中模式串next值的计算及匹配过程、改进的KMP中模式串nextval
提示:以下是本篇文章正文内容,下面案例可供参考(c++)
一BF算法
最好情况下的时间复杂度为O(n+m),n为主串长度,m为子串长度
最坏情况下的时间复杂度为O(n*m)。
代码如下(示例):
//暴力匹配算法
//需要传入主串,匹配位置,模式串(要匹配的串)
bool BF(string S,int pos,string T) {
//直接对主串的pos位置到pos+模式串的长度考试匹配,只要有一处不等就直接返回false
for (int i = 0; i < T.length();i++) {
if (T[i]!=S[pos+i]) {
return false;//匹配失败
}
}
return true;//匹配成功
}
接下来是经典的使用场景
使用这个算法主要就是可以得到模式串在主串的全部位置,所以需要一个循环来对主串全操作
int main() {
string s = "12341234567651日2任然";
string s1 = "12";
//输出主串中模式串所在的位置,
//主串最后不足模式串的长度的部分没有意思,因为一定不会存在想要的答案
//说实话,为了使用一个函数而写一个循环,我觉得这样有违写函数的目的,函数就是为了将操作变成一行
for (int i = 0; i < s.length()-s1.length();i++) {
if (BF(s,i,s1)) {
cout << i<<" ";
}
}
//结果0 4
return 0;
}
BF经典算法
虽然较长,但是在使用的时候非常方便,只需要传入主串,模式串,初始匹配位置,就可以返回第一个模式串的位置。
//这个算法只能返回一个位置
int BF(string S,string T,int pos) {
int i = pos, j = 0;
while (i < S.length()&&j<T.length()) {
//两串均为比较到串尾
if (S[i]==T[j]) {
i++; j++;
}else {
i = i - j + 1;//位置后移
pos = i;//更新pos的位置
j = 0;
}
}
if (j == T.length()) return pos;
else return -1;//没有找到返回-1
}
二.KMP算法
代码如下(示例):
我在一下代码中使用的unsigned(无符号位)都可以用int代替,我之所以这样是为了减少警告(小知识:串的长度的类型就是unsigned,即非负数,这个类型可以比int存储多一位二进制的数,即全部的二进制位都用来存储信息,没有符号位用来判断数据的正负)
有意思的next数组的数值仅与模式串有关。
//得到next数组
void get_next(int next[],string T) {
next[1] = 0; next[2] = 1;
unsigned i = 2, j = 1;//这里的i和j都代表数学位置,所以在下面的对串的所以的使用要-1
while (i <= T.length()) {
//如果两个位置的字符相等就让i后面一个位置等于j+1
if (j==0||T[i-1]==T[j-1]) {
i++, j++;
next[i] = j;//i和j都已自加
}else {
j = next[j];
}
}
}
//这个返回的是数学位置,不是索引,可以在返回的最后的-1即可
int KMP(string S,string T) {
unsigned i = 1, j = 1;
static int next[10];
get_next(next,T);
while (i<=S.length()&&j<=T.length()) {
if (j==0||S[i-1]==T[j-1]){
i++, j++;
}
else {
j = next[j];
}
}
if (j>T.length())return i - T.length()//返回数学位置
else return -1;
}
int main() {
string s = "1233414322";
string s1 = "233";
cout << KMP(s,s1);
return 0;
}
//结果为2
改进的next求解方法,减少模式串和主串的无用匹配
//改进的next求解方法
//计算next的修正值
void get_nextval(string T, int nextval[]) {
int i = 1, j = 0;
while (i < T.length()) {
if (j == 0 || T[i] == T[j]) {
i++, j++;
if (T[i] != T[j]) nextval[i] = j;
else nextval[i] = nextval[j];
}else j = nextval[j];
}
}
结束语:我自己能够在复习后理解,翻阅文章主要便于记忆