ACM学习历程27——模式匹配
来源:互联网 发布:没文凭找工作 知乎 编辑:程序博客网 时间:2024/06/05 01:15
模式匹配是数据结构中字符串的一种基本运算,给定一个子串,要求在某个字符串中找出与该子串相同的所有子串,这就是模式匹配,通常模式匹配算法可以通过以下方式求解。
一、BF朴素模式匹配
该算法思想主要依靠循环遍历比较,设目标串为S,模式串为T,在外层循环中变量i指向目标串的某个位置,在内层循环中变量j=i,k=0。从k和j的位置开始,若S[j]与T[k]相等则j和k同时向后移动,若k能移动到模式串的结尾,则i为模式匹配的其实位置。反之,若在移动的过程中存在S[j]与S[k]不相等的地方,则结束内层循环,并将i向下移动一个单位,同时在内层循环中再次将i赋值给j,0赋值赋给k。BF算法的实现方式如下:
#include<iostream>#include<string>using namespace std;void main(){ string s1,s2; int i=0,j=0,k=0; cout<<"s1:"; cin>>s1; cout<<"s2:"; cin>>s2; for(i=0;i<s1.length();i++) { j=i; k=0; while(j!=s1.length()&&k!=s2.length()) { if(s1[j]==s2[k]) { j++; k++; } else break; } if(k==s2.length()) { cout<<"The start pos:"<<i<<endl; break; } } if(i==s1.length()) cout<<"Not match!"<<endl;}测试输出:s1:123456789asds2:789aThe start pos:6
二、KMP模式匹配算法
KMP算法全称克努特—莫里斯—普拉特算法,该算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息,时间复杂度O(m+n)。KMP算法需要考虑如下几种情形:
2.1 情形一
从上面的关系可知,由于T串中T[1]不与后面的任意一个字符相等且S[1]==T[1],因此情形一匹配的部分属于唯一对应关系子串,但由于S[5]!=T[5],所以对于T串来说,下一次开始的匹配位置为S[5]和T[1]。
2.2 情形二
在情形二中存在匹配的部分S[1]==T[1],S[2]==T[2],但是在S[3]与T[3]的位置失配,考虑到T[1]==T[2]且T[1]!=T[3],那么下一次开始配置的位置将不再是T[1]与S[2],因为此种情况下由上述关系可知T[1]==S[2]的,所以开始匹配的位置为T[2]和S[3]。
2.3 情形三
在情形三中,下标从0—5对应位置的S[i]和T[i]相等,但是在下标为6的位置出现了失配,从上面给出的等量关系中可知,在模式串中T[1]==T[4],T[2]==T[5]且T[1]==S[4],T[2]==S[5],所以下一的判断匹配的位置可以从T[3]和S[6]的位置开始。
2.4 情形四
注:上述四种情况中,目标串和模式串的第一个位置存储的是串的长度。
2.5利用KMP算法需要求解next数组,通过这个数组可以在S[j]与S[k]不相等时,找到下一次回溯模式串回溯的下标。
2.5.1求解next数组
#include<iostream>#include<string>using namespace std;void get_next(int *T,int *next){ int i=0; int j=1; next[1]=0; int count=0; while(j<T[0]) { if(i==0 || T[i]==T[j]) { i++; j++; next[j]=i; } else { i=next[i]; } }}void main(){ int T[30]={11,'a','b','c','a','b','c','a','b','b','a','c'}; int next[25]; get_next(T,next); for(int i=1;i<=11;i++) cout<<next[i]<<" "; cout<<endl;}测试输出:0 1 1 1 2 3 4 5 6 1 2
2.5.2上述模式串是将字符的ASCII存储在数组数组中,数组的第一个位置存储模式串的长度,对于一个String类型的数据,由于第一个位置不是串的长度,因此需要对上面的代码进行适当的改动,代码如下:
#include<iostream>#include<string>using namespace std;void get_next(string T,int next[]){ int i=-1; int j=0; next[0]=-1; while(j<T.length()) { if(i==-1 || T[i]==T[j]) { i++; j++; next[j]=i; } else { i=next[i]; } }}void main(){ string T="abcabcabbac"; int next[30]; get_next(T,next); for(int i=0;i<T.length();i++) cout<<next[i]<<" "; cout<<endl;}测试输出:-1 0 0 0 1 2 3 4 5 0 1
2.5.3KMP算法
#include<iostream>#include<string>using namespace std;void get_next(string T,int next[]){ int i=-1; int j=0; next[0]=-1; int count=0; while(j<T.length()) { if(i==-1 || T[i]==T[j]) { i++; j++; if(T[i]==T[j]) next[j]=next[i]; else next[j]=i; } else { i=next[i]; } }}int Index_KMP(string s,string T,int pos){ int i=pos; int j=1; int next[30]; get_next(T,next); for(int k=0;k<T.length();k++) cout<<next[k]<<" "; cout<<endl; while(i<s.length()&&j<T.length()) { if(j==-1 || s[i]==T[j]) { i++; j++; } else j=next[j]; } return (j==T.length())?i-T.length():-1;}void main(){ string s="abcabcaabcabcabbacb"; string T="abcabcabbac"; cout<<s<<endl; cout<<T<<endl; int pos=Index_KMP(s,T,0); cout<<pos<<endl;}测试输出:abcabcaabcabcabbacbabcabcabbac-1 0 0 -1 0 0 -1 0 5 -1 17
- ACM学习历程27——模式匹配
- ACM学习历程1——输入输出语句
- ACM学习历程4——STL的使用
- ACM学习历程6——Vector向量容器
- ACM学习历程8——Vector应用
- ACM学习历程10——set集合容器
- ACM学习历程12——Map映照容器
- ACM学习历程13——multimap集合容器
- ACM学习历程17——bitset位集合容器
- ACM学习历程18——stack堆栈容器
- ACM学习历程21——各种排列组合问题
- ACM学习历程22——进制转换
- ACM学习历程23——最小周期串问题
- ACM学习历程24——最大回文子串
- ACM学习历程25——高精度四则运算
- ACM学习历程26——KMP算法
- ACM学习历程28——利用数组下标
- ACM学习历程29——搜索算法
- PLSQL Developer连接远程oracle配置
- Eclipse Meaven Spring SpringMVC Mybaits整合
- jasperreport web项目图标不显示问题
- Intellij IDEA 的前进后退
- Leetcode 7. Reverse Integer
- ACM学习历程27——模式匹配
- HTTP 协议入门
- UIScrollView的属性总结
- LeetCode – Kth Largest Element in an Array (Java)
- GDB core 问号
- Android中Sqlite的使用及性能优化
- 根据筛法求素数,然后求最大公约数
- ThreadLocal
- Windows Server 2012 在桌面上显示”我的电脑