ACM学习历程27——模式匹配
2016-09-02 12:53
225 查看
模式匹配是数据结构中字符串的一种基本运算,给定一个子串,要求在某个字符串中找出与该子串相同的所有子串,这就是模式匹配,通常模式匹配算法可以通过以下方式求解。
一、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算法的实现方式如下:
二、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数组
2.5.2上述模式串是将字符的ASCII存储在数组数组中,数组的第一个位置存储模式串的长度,对于一个String类型的数据,由于第一个位置不是串的长度,因此需要对上面的代码进行适当的改动,代码如下:
2.5.3KMP算法
一、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:123456789asd s2:789a The 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; } 测试输出: abcabcaabcabcabbacb abcabcabbac -1 0 0 -1 0 0 -1 0 5 -1 1 7
相关文章推荐
- ACM学习历程—HDU 5012 Dice(ACM西安网赛)(bfs)
- ACM学习历程—FZU2148 Moon Game(计算几何)
- ACM学习历程——POJ 2376 Cleaning Shifts(贪心)
- ACM学习历程——UVA11111 Generalized Matrioshkas(栈)
- ACM学习历程——UVA442 Matrix Chain Multiplication(栈)
- ACM学习历程—HDU 5023 A Corrupt Mayor's Performance Art(广州赛区网赛)(线段树)
- ACM学习历程——POJ1260 Pearls(动态规划)
- ACM学习历程——POJ3295 Tautology(搜索,二叉树)
- ACM学习历程—HDU2222 Keywords Search(字典树)
- ACM学习历程——UVA540 Team Queue(队列,map:Hash)
- ACM学习历程—HDU4969 Just a Joke(物理题)
- ACM学习历程——HDU4814 Golden Radio Base(数学递推) (12年成都区域赛)
- ACM学习历程——HDU4472 Count(数学递推) (12年长春区域赛)
- ACM学习历程——HDU1331 Function Run Fun(锻炼多维dp的打表)
- ACM学习历程—HDU1028 Ignatius and the Princess(组合数学)
- ACM学习历程—Rotate(HDU 2014 Anshan网赛)(几何)
- ACM学习历程——ZOJ 3822 Domination (2014牡丹江区域赛 D题)(概率,数学递推)
- ACM学习历程——HDU5017 Ellipsoid(模拟退火)(2014西安网赛K题)
- ACM学习历程——UVA127 "Accordian" Patience(栈, 链表)
- ACM学习历程——UVA10112 Myacm Triangles(计算几何,多边形与点的包含关系)