0.概述
本文将从以下几个方面介绍串的基本知识模式匹配算法:
- 以思维导图的方式介绍串的基本知识
- 介绍串的基本存储结构
- 介绍BF算法(文末给出代码实现)
- 介绍
KMP算法
,包括 next数组手算方法(文末给出KMP算法实现)- 实现代码(BF算法、KMP算法)
1. 串的基本知识
字符串的基本操作,请参考我的另一篇博客:串——字符串的基本操作.
2.串的存储结构
(1)顺序存储
(2)链式存储
3.BF算法(朴素模式匹配算法)
文末附实现代码!!!
查找失败时间复杂度
4.KMP算法(重点!!!)
文末附KMP实现算法!!!
(1)next 数组计算(
手算
)
- 计算 next数组 ,有两种方式(下标从0或1开始),以下介绍以1下标开始的情况,为了保证
主串标识 i 与匹配串标识 j 同步++
,所以将next[1]=0
,之后分析情况见下图:- 注: 下标从 0 开始分析方法与从 1 开始分析方法相同,将
next[0]=-1
即可,且二者 next 数组存储元素值,相差1
(读者可按相同手算方式自行分析)- next数组下标为1 (两个字符串匹配从
脚标1
开始),分析方法
- 示例:
(2)KMP算法
- 时间复杂度为:
O(m+n)
O(m):建立next数组的时间
O(n):匹配字符的时间
5.实现代码
1.BF算法
#include<bits/stdc++.h>
using namespace std;
//BF算法——朴素模式匹配算法
int BF(string s1,int n,string s2,int m){
int start=0; //表示正在匹配 以start 角标开始的子串 (回溯)
int i=start;
int j=0; // 表示匹配到 模式串的第j个位置
while(i<n&&j<m){
if(s1[i]==s2[j]){ //字串与模式串 ij字符 匹配成功
i++;
j++;
}else{ // 模式串开始匹配新的串
start++;
i=start;
j=0;
}
}
//扫描到s2末尾 非存储字符位置
if(j==m){ // 匹配成功(模式串被扫描完毕)
return start;
}
return -1;
}
int main(){
string s1,s2; // s1为主串、s2为模式串
cin>>s1>>s2;
int n=s1.length();
int m=s2.length();
int result=BF(s1,n,s2,m); // 获取模式匹配结果
if(result!=-1){
cout<<"模式匹配成功:"<<result<<endl;
}else{
cout<<"模式匹配失败!"<<endl;
}
return 0;
}
2.KMP算法(字符串形式,以下标0开始)
#include<bits/stdc++.h>
using namespace std;
//传入是字符串,所以从第0个位置开始比较
int KMP(string s1,int n,string s2,int m,int next[]){
//传入是字符串,所以从第0个位置开始比较
int i=0;
int j=0;
while(i<n&&j<m){
if(j==-1||s1[i]==s2[j]){
i++;
j++;
}else{
j=next[j]; //利用next数组进行回溯
}
}
if(j==m){
return i-m; // 返回匹配成功起始位置
}
return -1;
}
int main(){
string s1="ababaababcb";
string s2="ababc";
int n=s1.length();
int m=s2.length();
int next[]={-1,0,0,1,2};
int result=KMP(s1,n,s2,m,next);
if(result>-1){
cout<<"匹配成功:"<<result<<endl;
}else{
cout<<"匹配失败!"<<endl;
}
return 0;
}
3.KMP算法(字符数组形式,以下标1开始)
#include<bits/stdc++.h>
using namespace std;
//传入的是字符数组,从1位置开始比较
int KMP(char ch1[],int n,char ch2[],int m,int next[]){
int i=1;
int j=1;
while(i<=n&&j<=m){ //下标从1开始,所以是 《=
if(j==0||ch1[i]==ch2[j]){
i++;
j++;
}else{
j=next[j];
}
}
if(j>m){
return i-m;
}
return 0;
}
int main(){
char ch1[]={' ','a','b','a','b','a','a','b','a','b','c','b'};
char ch2[]={' ','a','b','a','b','c'};
int n=sizeof(ch1)/sizeof(ch1[0])-1;
int m=sizeof(ch2)/sizeof(ch2[0])-1;
int next[]={0,1,1,2,3};
int result=KMP(ch1,n,ch2,m,next);
if(result>0){
cout<<"匹配成功:"<<result<<endl;
}else{
cout<<"匹配失败!"<<endl;
}
return 0;
}