前言
串是一系列字符以线性关系连接而成的数据结构,其基本实现靠的还是线性表,关于它的数据结构在这里就不赘述了,本章主要讲关于字符串匹配很重要的两个算法,一个是BF另一个是KMP
一、BF算法
一般字符串都喜欢把第一个位置空出来存放长度之类的,这里我们默认数据从数组下标为1处开始。BF算法的过程就是逐个校对字符,出现错误后就回到第一个校对字符的下一位,首先把位置给到i和j,当下标不超过字符串长度时,不停地对比字符,对比成功下标+1,对比失败子串下标归零,模板下标回到上次比较位置地下一个位置,循环结束后判断j的值,如果等于子串长度,说明退出循环是因为找到了子串,否则是因为模板已经遍历完了,返回对应的值就好
int index_BF(SString S, SString T, int pos){
// S是模板字符串,T是子串,pos是指在S的第几个字符开始匹配
int i = pos;
int j = 1;
while(i < S.length && j < T.length){
if(S[i] == T[j]){
// 匹配正确,继续对比下一个字符
++i;
++j;
}else{
// 匹配错误下标更新
i = i - j + 2;
j = 0;
}
// 成功找到子串,返回子串在模板中第一个位置的下标
if(j == T.length-1) return i - T.length + 1;
return 0;
}
}
二、KMP算法
KMP算法就是不移动模板的游标,不同位置匹配失败之后子串游标的调整不一样,以此来达到提高效率的目的,具体思路就不说了大家有兴趣可以参考网上大佬们的视频(这里是讲代码的),这里直接上代码
void get_next(SString T, int &next[]){
int i = 1, j = 0;
next[i] = 0;
while(i < T[0]){ // T[0]表示这个串的长度
if(j == 0 || T[i] == T[j]) next[++i] = ++j;
else j = next[j];
}
}
int index_KMP(SString S, SSreing T, int pos){
int i = pos, j = 1;
while(i < S[0] && j < T[0]){
if(j == 0 || S[i] == T[j]){
++i;
++j;
}else j = next[j];
}
if(j == T[0]) return i - T[0] + 1;
return 0;
}
这里还有一个关于next数组的优化,核心思想就是,我当前字符匹配失败了,回溯过去,如果回溯的位置的字符和我当前匹配的字符一样,那就说明百分百匹配失败,那我直接拿他的回溯位置作为我的回溯位置就好了
void get_nextval(SString T, int &next[]){
int i = 1, j = 0;
next[i] = 0;
while(i < T[0]){ // T[0]表示这个串的长度
if(j == 0 || T[i] == T[j]) next[++i] = ++j;
else j = next[j];
} // 前面的代码和next的一样,关键在于下面的更新
for(i = 1; i < T[0]; ++i){
if(T[i] == T[next[i]]) next[i] = next[next[i]];
}
}