模式匹配
index(StringS,String T,int pos)
T称为模式串
S称为主串
简单的想法:
从主串的i位置开始匹配,逐一比较,如果当T完成之前都匹配,说明i就是匹配T的开始位置。
代码:
int Index1(string s,string t,int& pos)
{
int i,j;
for(i=0;i<=s.size()-t.size();i++)
{
bool flag=true;
for(j=0;j<t.size();j++)
{
if(s[i+j]!=t[j])
{
flag=false;
break;
}
}
if(flag==true)
{
pos=i; //第一个匹配的位置
break;
}
}
return 0;
}
时间复杂度:O(m*n)
S="ababcabcacbac"
T="abcac"
当状态为(下标从1开始):
这个时候比较S[7],T[5]不相等,如果是传统的做法是,i回到4(因为S从3开始匹配失败了),j回到1。
但是实际上,i=4,j=1; i=5,j=1; i=6,j=1其实是不用比较的,而是直接比较i=7,j=2开始就好了也就是说其实i是不用回溯的,现在的问题就是把模式串T向前移动多远?
考虑一般情况:
如果现在主串S已经匹配到i,模式串T已经匹配到j了,但是这个时候失败了。
现在做个假设,假设把模式串向前移动,让T[K]和S[i]对齐,注意S[i]是主串刚才匹配失败的地方。 那么就有一下结论:
- T1T2T3...TK-1 == Si-k+1Si-k+2...Si-1 ; 并且没有k' 大于 k使得前面的等式满足,也就是k满足,在模式串中最长的前缀和主串已经匹配了
- 而刚才在匹配S[i],T[j]失败可以得知,之前的
Tj-k-1Tj-k-2Tj-k-3...Tj-1 == Si-k+1Si-k+2...Si-1 都是相等的
1,2可得:
T1T2T3...TK-1 == Tj-k-1Tj-k-2Tj-k-3...Tj-1
也就是说模式串自己跟自己匹配是可以得到上述到底要移动多远的信息!!
现在定义:
0 if(j==1,第一个为0,下标开始的地方为0)
next[j]= max{ k | (1<k<j && T1T2T3...TK-1 == Tj-k-1Tj-k-2Tj-k-3...Tj-1 ) } ;
其他情况为1
重点:next[j]也就是说在T[j]位置以前k-1可字符和T开始的k-1个字符是完全匹配的,注意是k-1,不是k
比如:
具体如何求得next[]:(字符串是从1开始
- 首先:next[1]=0;
- 设nextj]=k,即有
T1T2T3...TK-1 == Tj-k-1Tj-k-2Tj-k-3...Tj-1
分两种情况:
1 : Tk=Tj; 这个时候next[j+1]=k+1=next[j]+
2:如果Tk!=Tj
j= 1 2 … 6 8
模式串: a b a a b c a c
next[j] 0 1 1 2 2 3
假设现在j=6,T[3]!=T[6];要计算next[7]的值!!
现在模式串即时主串也是模式串: 向前滑动next[k]=f个距离。
为什么是next[k]个距离呢??? 见上面分析。。
故求得next函数的程序:
void get_next(string T,int next[], int len)
{
//T的下标从1开始
int i=1,j=0;
next[1]=0;//起始元素初始化为0
while(i<len)
{
if(j==0) //注意j=0的时候说明i+1之前T自己匹配自己长度为0,所以next[i+1]=1,并且j-1,
{
next[i+1]=1;
i++;
j=1;
}
else if(T[i]==T[j])
{
next[i+1]=j+1;
i++;j++;
}
else
j=next[j];//模式串向前移动使得T1[i]=和T2[j]对齐
}
}
在主串S中找到T串,返回开始匹配的位置
void Index_KMP(string S,int slen,string T,int tlen,int pos)
{
int i=pos,j=1;
while(i<=slen && j<=tlen) //下标从1开始,最后是slen和tlen
{
if(j==0) //j==0说明模式串j之前的,从1开始的子串没有可以和主串在i开始前的一段匹配,
//那只能从i+1,j=1开始匹配,这个和前面j=0是一样的
{
i++;
j=1;
}
if(S[i]==T[j]) //如果相等继续比较
{
i++;
j++;
}
else
{
j=next[j];//模式串向前移动,使得j和i对齐比较
}
}
if(j>tlen) //说明有匹配的
{
return i-tlen;
}
else
return -1;//说明没有匹配上
}