字符串-模式匹配算法
1:BF(brute-force)模式匹配
int Index(char S[],int pos,char T[]) { int i=pos;//主串开始位置 int j=1; while(i<=strlen(S)&&j<=strlen(T)) { if(S[i]==T[j]) { i++; j++; } else { i=i-j+2;//主串回溯到该位置重新比较 j=1; } } if(j>strlen(T)) { return i-strlen(T); } else { return 0; } }
2:KMP模式匹配
解析 next函数 当j=1 0 当此集合不为空 max{k|1<k<j且'T1.....T(k-1)'='T(j-k+1)...t(j-1)} 其他 1 当next函数定义中的集合不为空时,next[j]的值等于串’T1T2…T(j-1)'的真前缀子串和真后缀子串相等时的最大子串长度+1 a b a a b c a c j 1 2 3 4 5 6 7 8 j=1 0 j=2 1 j=3 a ab 0+1=1 j=4 a aba 1+1=2 j=5 b abaa 1+1=2 j=6 c abaab 2+1=3 j=7 a abaabc 0+1=1 j=8 c abaabca 1+1=2 在匹配过程中Si=Tj,则i和j分别增1; 否则,i不变,而j退到next[j]位置再比较(即Si和Tnext[j]进行比较), 若相等,则指针各自增1, 否则j再退到下一个next值得位置 此程序中,next 数组使用的下标初始值为 1 , next[0] 没有用到(也可以存放 next 数组的长度)。 而串的存储是从数组的下标 0 开始的,所以程序中为 T[i-1] 和 T[j-1]。 具体的算法如下: 模式串T为(下标从1开始):“abcabac” next数组(下标从1开始): 01 第三个字符 ‘c’ :由于前一个字符 ‘b’ 的 next 值为 1 ,取 T[1] = ‘a’ 和 ‘b’ 相比较,不相等,继续;由于 next[1] = 0,结束。
‘c’ 对应的 next 值为1;(只要循环到 next[1] = 0 ,该字符的 next 值都为 1 ) 模式串T为: “abcabac” next数组(下标从1开始):011 第四个字符 ’a‘ :由于前一个字符 ‘c’ 的 next 值为 1 ,取 T[1] = ‘a’ 和 ‘c’ 相比较,不相等,继续;由于 next[1] = 0 ,结束。
‘a’ 对应的 next 值为 1 ; 模式串T为: “abcabac” next数组(下标从1开始):0111 第五个字符 ’b’ :由于前一个字符 ‘a’ 的 next 值为 1 ,取 T[1] = ‘a’ 和 ‘a’ 相比较,相等,结束。
‘b’ 对应的 next 值为:1(前一个字符 ‘a’ 的 next 值) + 1 = 2 ; 模式串T为: “abcabac” next数组(下标从1开始):01112 第六个字符 ‘a’ :由于前一个字符 ‘b’ 的 next 值为 2,取 T[2] = ‘b’ 和 ‘b’ 相比较,相等,所以结束。
‘a’ 对应的 next 值为:2 (前一个字符 ‘b’ 的 next 值) + 1 = 3 ; 模式串T为: “abcabac” next数组(下标从1开始):011123 第七个字符 ‘c’ :由于前一个字符 ‘a’ 的 next 值为 3 ,取 T[3] = ‘c’ 和 ‘a’ 相比较,不相等,继续;由于 next[3] = 1 ,
所以取 T[1] = ‘a’ 和 ‘a’ 比较,相等,结束。
‘a’ 对应的 next 值为:1 ( next[3] 的值) + 1 = 2 ; 模式串T为: “abcabac” next数组(下标从1开始):0111232
void GetNext(int *next,char *T) { // a b a a b c a c //j 1 2 3 4 5 6 7 8 //k 0 1 2 3 4 5 6 7 int i=1,j=0; next[i]=0; while(i<strlen(T))//1<8 2<8 2<8 3<8 { if(j==0||T[i-1]==T[j-1])//k==0,t[1]=t[0] 2=1 2=0 3=2 { ++i;//j=2 3 4 ++j;//k=1 2 3 next[i]=j;//next[2]=1,next[3]=2 next[4]=3 } else { j=next[j];//0 } } } int KMP(char *s,char *t) { int next[10]; GetNext(next,t); int i=1,j=1; while(i<=strlen(s)&&j<strlen(t)) { //j==0:代表模式串的第一个字符就和当前测试的字符不相等;S[i-1]==T[j-1], //如果对应位置字符相等,两种情况下,指向当前测试的两个指针下标i和j都向后移 if(j==0||s[i-1]==t[j-1]) { i++; j++; } else { j=next[j];//如果测试的两个字符不相等,i不动,j变为当前测试字符串的next值 } } if(j>strlen(t))//如果条件为真,说明匹配成功 { return i-strlen(t); } return -1; } int main() { int i=KMP("ababcabcacbab","abcac"); printf("%d",i); return 0; }
3:升级KMP模式匹配
解析 模式串T:a b c a c next :0 1 1 1 2 在模式串“abcac”中,有两个字符 ‘a’,我们假设第一个为 a1,第二个为 a2。 在程序匹配过程中,如果 j 指针指向 a2 时匹配失败,那么此时,主串中的 i 指针不动,j 指针指向 a1 ,很明显, 由于 a1==a2,而 a2!=S[i],所以 a1 也肯定不等于 S[i]。 为了避免不必要的判断,需要对 next 数组进行精简, 对于“abcac”这个模式串来说,由于 T[4] == T[next[4]] , 所以,可以将next数组改为: 模式串T:a b c a c next :0 1 1 0 2
void GetNext(int *next,char *T) { int i=1,j=0; next[i]=0; while(i<strlen(T)) { if(j==0||T[i-1]==T[j-1]) { ++i; ++j; if (T[i-1]!=T[j-1]) { next[i]=j; } else{ next[i]=next[j]; } } else { j=next[j];//0 } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?