严蔚敏-数据结构-kmp算法详解

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
7
例如t="abab",由于"t0t1" ="t2t3"(这里k=1,j=3),则 存在真子串。设s="abacabab",t="abab",第一次匹配 过程如下所示。
第 1次 匹 配 s= abacabab t= abab
i= 3 j= 3
失 败
此时不必从i=1(i=i-j+1=1),j=0重新开始第二次匹 配。因t0≠t1,s1=t1,必有s1≠t0,又因t0 =t2,s2=t2,所以必有 s2=t0。因此,第二次匹配可直接从i=3,j=1开始。
j=0;k=-1;next[0]=-1; while (j<t.len-1) { if (k==-1 || t.data[j]==t.data[k])
/*k为-1或比较的字符相等时*/ { j++;k++;
next[j]=k; } else k=next[k]; } }
由模式串t 求 出 next 值 的算法
这时,应有
t:t0 t1 …tj-1 tj tj+1…sm -1
"t0t1…tj-1"="si-jsi-j+1…si-1"
(4.1)
如果在模式t中,
"t0t1…tj-1"≠"t1t2…tj"
(4.2)
4
则回溯到si-j+1开始与t匹配,必然“失配”,理由 很简单:由(4.1)式和(4.2)式综合可知:
12
例如,设目标串s=“aaabaaaab”,模式串t=“aaaab”。 s的长度为n(n=9),t的长度为m(m=5)。用指针i指示目 标串s的当前比较字符位置,用指针j指示模式串t的当 前比较字符位置。KMP模式匹配过程如下所示。
13
j
0
1
2
3
4
t[j]
a
a
a
a
b
next[j] -1
0
1
2
3
{ i++;j++; } /*i,j各增1*/
else j=next[j]; /*i不变,j后退*/
}
if (j>=t.len) v=i-t.len; /*返回匹配模式串的首字符下标*/
else v=-1;
/*返回不匹配标志*/
return v;
11
}
ቤተ መጻሕፍቲ ባይዱ
设主串s的长度为n,子串t长度为m。 在 KMP 算 法 中 求 next 数 组 的 时 间 复 杂 度 为 O(m),在后面的匹配中因主串s的下标不减即不回溯, 比较次数可记为n,所以KMP算法总的时间复杂度为 O(n+m)。
i= 3 失败
j= 1 ,j= n e x t[1 ]= 0
第 4次匹配
s=aaabaaaa b
t= a a a a b
i= 3 失败
j=0,j=next[0]= -1
第 5次匹配
s=aaabaaaa
i= 9
成功
b t= a a a a b
j=5,返 回 10-5=4
14
上述定义的next[]在某些情况下尚有缺陷。 例如,模式“aaaab”在和主串“aaabaaaab”匹配时, 当i=3,j=3时,s.data[3]≠t.data[3],由next[j]的指示还需进 行i=3、j=2,i=3、j=1,i=3、j=0等三次比较。实际上,因 为模式中的第1、2、3个字符和第4个字符都相等,因此, 不需要再和主串中第4个字符相比较,而可以将模式一 次向右滑动4个字符的位置直接进行i=4,j=0时的字符 比较。
t: t0 t1 … tk-1 tk … tj-1 tj tj+1 … sm-1 t 右滑j-k位
s: s0 s1 … si-j si-j+1 … si-k si-k+1 … si-1 si si+1 … sn-1
t: t0 t1 … tk-1 tk … tj-1 tj tj+1 … sm-1
说明下一次可直接比较si和tk,这样,我们可以 直接把第i趟比较“失配”时的模式t从当前位置直 接右滑j-k位。而这里的k即为next[j]。
大家好
1
4.3.2 KMP算法
KMP算法是D.E.Knuth、J.H.Morris和V.R.Pratt 共同提出的,简称KMP算法。该算法较BF算法有较 大改进,主要是消除了主串指针的回溯,从而使算法效 率有了某种程度的提高。
2
所谓真子串是指模式串t存在某个k(0<k<j),使 得"t0t1…tk " = " tj-ktj-k+1…tj "成立。
10
int KMPIndex(SqString s,SqString t)
{ int next[MaxSize],i=0,j=0,v; GetNext(t,next);
KMP算法
while (i<s.len && j<t.len)
{ if (j==-1 || s.data[i]==t.data[j])
第 1次匹配 第 2次匹配 第 3次匹配
s=aaabaaaa b t= a a a a b s=aaabaaaa b t= a a a a b s=aaabaaaa b
t= a a a a b
i= 3 失败
j= 3 ,j= n e x t[3 ]= 2
i= 3 失败
j= 2 ,j= n e x t[2 ]= 1
"t0t1…tk-2"≠" tj-k+1tj-k+2…tj-1" 且
"t0t1…tk-1"="tj-ktj-k+1…tj-1“ 才有
"tj-ktj-k+1…tj-1"="si-ksi-k+1…si-1"="t0t1…tk-1"
6
s: s0 s1 … si-j si-j+1 … si-k si-k+1 … si-1 si si+1 … sn-1
"t0t1…tj-1"≠"si-j+1si-j+2…si" 既然如此,回溯到si-j+1开始与t匹配可以不做。那 么,回溯到si-j+2开始与t匹配又怎么样?从上面推理 可知,如果
"t0t1…tj-2"≠"t2t3…tj" 仍然有
"t0t1…tj-2"≠"si-j+2si-j+3…si"
5
这样的比较仍然“失配”。依此类推,直到对于 某一个值k,使得:
例如,t= "abab", 即t0t1=t2t3 也就是说, “ab”是真子串。 真子串就是模式串中隐藏的信息,利用它来提高 模式匹配的效率。
3
一般情况:设主串s="s0s1…sn-1",模式t="t0t1…tm-1", 在进行第i趟匹配时,出现以下情况:
s:s0s1…si-jsi-j+1…si-1 si si+1…sn-1
8
为此,定义next[j]函数如下:
next[j]=
max{k|0<k<j,且“t0t1…tk-1”=“tj-ktj-k+1…tj-1” } 当此集合非空时
-1
当j=0时
0
其他情况
t=“abab”对应的next数组如下:
j
0
1
2
3
t[j]
a
b
a
b
next[j] -1
0
0
1
9
void GetNext(SqString t,int next[]) { int j,k;
相关文档
最新文档