KMP算法
2016-05-29 23:24
387 查看
推荐大牛讲解KMP的文章,比我讲的好10000倍,就是长一点: http://blog.csdn.net/v_july_v/article/details/7041827
主串: a b a b c a b c a c b a b
匹配串: a b c a c
i:主串当前下标
j:匹配串当前下标
第一趟匹配: a b a b c a b c a c b i = 3
a b c a c j = 3
第二趟匹配: a b a
b c a b c a c b i = 7
a b c a c
j = 5
第三趟匹配: a b a
b c a b
c a c b i = 7
(a) b
c a c
j = 2
我们看第三趟匹配直接从 b 处开始,这是利用了第二趟匹配的结果。
1:在第二趟匹配在 c 处失败后,按照常规应该是从主串下一位即i=4,j=1开始匹配,依次类推。
2:但是由于和主串中的abca是匹配的,注意:abca
3:因为a != b != c; 但是 a = a;所以直接从b开始匹配就好了。
4:注意对于在第三趟匹配中。j=1的(a)所在位置i=7 不正是 第二趟匹配中 j = 4的a所在的位置吗。
看出来没: 每次选择下一趟匹配时,(a)占了a的位置,为什么呢。 因为他两个相等阿。额,废话。
5: 所以对于KMP算法: 如在 p = a b c a c 中如在
j=5出发生失配时,选择下一步 j=k 的其实是求对于
sn = a b c a中的k值。 使得s0,s1...s(k-1) = sn,s(n-1),...,s(n-k+1) = p(j-k+1)...p(j-1)(j=5)
在这里 a = a 所以 在j=5处失配时, k(j
4000
=5) = 2;(即当模式串在j=5 处失配时,存j=k=2处在和主串比较。)
再设想如果 P = a b
c a c b 当在j = 6即b 处失配时 k=3 = k(j=5) + 1;
在下面中,P 相当于 a b c a c b 。
当j = 5=c时。 P1P2……P(k-1) = a; P(j-k+1)……P(j-1)
= a;
当j
= j+1 = b时。 P1P2……P(k-1)Pk = b;
P(j-k+1)……P(j-1)Pj = b;
-----------------------------------------------------------------------------------------------
1:设模式串P
= P1P2….Pk’……P(k-1)Pk……P(j-k+1)……P(j-1)P(j+1)……Px
设主串S;
int i = 主串中位置. int j=模式串中位置; (从1开始计数)
int k = 模式串在j处”失配”后的滑动位置.
2:KMP算法推导:
所以有: P1……Pk = S(i-k+1)……S(i-1) = P(j-k+1)……P(j-1)
所以k值变得只和模式串自己有关—->我们就可以计算出模式串在每个位置失配后的K值,然后用这些值来进行字符串匹配.
所以有模式串函数next:
3:根据next函数计算next[]数组.
设模式串P = P1P2…..Px…..Pk’….P(k-k’+1)….P(k-1)Pk……P(j-k+1)……P(j-1)PjP(j+1)……Px
如果P 在 j 处发生了失配,对应为next[j]=k.所以有: P1……P(k-1) = P(j-k+1)……P(j-1)
next[1] = 0;
伪代码如下:
4:改进
next[] = 0 1 2 3 4
设模式串: P = a a a a b (int j)
设主串: S = a a a b a a a a b (int i)
可以看到P[4] != S[4] 所以next[4]=3将P向右滑动如下:
主串: a b a b c a b c a c b a b
匹配串: a b c a c
i:主串当前下标
j:匹配串当前下标
第一趟匹配: a b a b c a b c a c b i = 3
a b c a c j = 3
第二趟匹配: a b a
b c a b c a c b i = 7
a b c a c
j = 5
第三趟匹配: a b a
b c a b
c a c b i = 7
(a) b
c a c
j = 2
我们看第三趟匹配直接从 b 处开始,这是利用了第二趟匹配的结果。
1:在第二趟匹配在 c 处失败后,按照常规应该是从主串下一位即i=4,j=1开始匹配,依次类推。
2:但是由于和主串中的abca是匹配的,注意:abca
3:因为a != b != c; 但是 a = a;所以直接从b开始匹配就好了。
4:注意对于在第三趟匹配中。j=1的(a)所在位置i=7 不正是 第二趟匹配中 j = 4的a所在的位置吗。
看出来没: 每次选择下一趟匹配时,(a)占了a的位置,为什么呢。 因为他两个相等阿。额,废话。
5: 所以对于KMP算法: 如在 p = a b c a c 中如在
j=5出发生失配时,选择下一步 j=k 的其实是求对于
sn = a b c a中的k值。 使得s0,s1...s(k-1) = sn,s(n-1),...,s(n-k+1) = p(j-k+1)...p(j-1)(j=5)
在这里 a = a 所以 在j=5处失配时, k(j
4000
=5) = 2;(即当模式串在j=5 处失配时,存j=k=2处在和主串比较。)
再设想如果 P = a b
c a c b 当在j = 6即b 处失配时 k=3 = k(j=5) + 1;
在下面中,P 相当于 a b c a c b 。
当j = 5=c时。 P1P2……P(k-1) = a; P(j-k+1)……P(j-1)
= a;
当j
= j+1 = b时。 P1P2……P(k-1)Pk = b;
P(j-k+1)……P(j-1)Pj = b;
-----------------------------------------------------------------------------------------------
1:设模式串P
= P1P2….Pk’……P(k-1)Pk……P(j-k+1)……P(j-1)P(j+1)……Px
设主串S;
int i = 主串中位置. int j=模式串中位置; (从1开始计数)
int k = 模式串在j处”失配”后的滑动位置.
2:KMP算法推导:
1 2 3 4 5 | while (i < S.length && j < T.length){ if (P[j] != p[i]){ //也就是主串中的第i个字符和模式串中的第j个字符”失配”. //按照一般的方法,应该{ j=1;}从主串的下一个字符位置开始重新比较. //根据KMP算法(即根据以前比较的结果){ j=k ;} 从P[k]开始和主串比较. } |
所以k值变得只和模式串自己有关—->我们就可以计算出模式串在每个位置失配后的K值,然后用这些值来进行字符串匹配.
所以有模式串函数next:
3:根据next函数计算next[]数组.
设模式串P = P1P2…..Px…..Pk’….P(k-k’+1)….P(k-1)Pk……P(j-k+1)……P(j-1)PjP(j+1)……Px
如果P 在 j 处发生了失配,对应为next[j]=k.所以有: P1……P(k-1) = P(j-k+1)……P(j-1)
next[1] = 0;
123456789101112131415161718 | //如果P在j+1处发生了失配: if (Pk = Pj) { P1......P(k- 1 )Pk = P(j-k+ 1 )......P(j- 1 )Pj //所以:next[j+1] = next[j]+1 = k+1;} if (Pk != Pj){ //所以要找P1P2...Px = P(j-x+1).....P(j-1)Pj //怎么找这个x呢: //可以设想模式串为: P2 = P(j-x+1).....P(j-1)Pj要在P中进行模式匹配,现在k处发生失配,所 //以要从P2[k'=next[k]]处来进行下一步匹配了. //所以有P1...P(k'-1) = P(k-k'+1)...P(k-1) = P(j-k'+1)...P(j-1) if (P[k'] = P[j]) { P1...P(k '-1)Pk' = P(j-k'+ 1 )...P(j- 1 )Pj //所以: next[j+1] = next[k]+1 = k'+1 } else { //重复上述过程,求k".....,如果结果不存在,next[j+1] = 1 } } |
1 2 3 4 5 6 7 8 | int [] getNext(String t){ int [] next ; j= 1 ; next[ 1 ] = 0 ;k= 0 ; //next数组从1开始数,即从next[1]开始 while (j <= t.length){ if (k== 0 || p[j] = p[k]){ j++;k++; next[j] = k; } else k = next[k]; } } |
next[] = 0 1 2 3 4
设模式串: P = a a a a b (int j)
设主串: S = a a a b a a a a b (int i)
可以看到P[4] != S[4] 所以next[4]=3将P向右滑动如下:
S = a a a b a a a a b P = a a a a b 但是由于P[4] = P[3] = P[3] = P[1],其实可以直接滑动如下:
S = a a a b a a a a b P = a a a a b 这就是说: 当在j=4处发生失配时,取j = next[4].但是P[next[4]] = P[4] 所以肯定:S[i] != P[next[4]] 依次类推 就要取 j = next[j] 所以发现S[i] != P[next[4]] 这个是已知的,因为P[next[4]] = P[4],所以不需要比较S[i] 和 P[next[4]]. 也就是说 next数组中.可以直接让 next[4] = next[next[4]],依次类推 新的next[] = 0 0 0 0 4 所以新的为代码如下:
12345678910111213 | int [] getNext(String t){ int [] next ; j= 1 ; next[ 1 ] = 0 ;k= 0 ; //next数组从1开始数,即从next[1]开始 while (j <= t.length){ if (k== 0 || p[j] = p[k]){ j++;k++; if (p[j] != p[k]) next[j] = k; else next[j] = next[k]; } else k = next[k]; } } |
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析