KMP算法---理解
2013-06-25 21:51
211 查看
一. 简单匹配算法
简单匹配算法,又称为朴素的模式匹配算法。简单匹配算法回溯的是i,不是j。先来看一个简单匹配算法的例子:
public class KMP_test {
/*
* 若串 S 中从第pos(S 的下标0≤pos<StrLength(S))个字符 起存在和串 T 相同的子串,则称匹配成功,返回第一个
* 这样的子串在串 S 中的下标,否则返回 -1
*/
public static int find(String src, String target, int i) {
char[] sc = src.toCharArray();
char[] tc = target.toCharArray();
int j = 0;
while ((i + j) < sc.length && j < tc.length) {
if (sc[i + j] == tc[j]) {
j++;// 继续比较后一字符
} else {
i++; // 重新开始新的一轮匹配,i+1,j归零
j = 0;
}
}
if (j == tc.length)
return i; // 匹配成功 返回下标
else
return -1;// 串S中(第pos个字符起)不存在和串T相同的子串
}
public static void main(String[] args) {
String src = "keylovktyuy";
String target = "vkty";
System.out.println(find(src, target, 0));
// true代表找到了,false代表木有找到,
System.out.println(find(src, target, 0) == -1 ? false : true);
}
}
此算法的思想是直截了当的:将主串S中某个位置i起始的子串和模式串T相比较。即从 j=0 起比较 S[i+j] 与 T[j],若相等,则在主串 S 中存在以 i 为起始位置匹配成功的可能性,继续往后比较( j逐步增1 ),直至与T串中最后一个字符相等为止,否则改从S串的下一个字符起重新开始进行下一轮的"匹配",即将串T向后滑动一位,即 i 增1,而 j 退回至0,重新开始新一轮的匹配。即不断回溯的是i,不是j。
例如:在串S=”abcabcabdabba”中查找T=” abcabd”(我们可以假设从下标0开始):先是比较S[0]和T[0]是否相等,然后比较S[1] 和T[1]是否相等…我们发现一直比较到S[5] 和T[5]才不等。如图:
当这样一个失配发生时,T下标必须回溯到开始,S下标回溯的长度与T相同,然后S下标增1,然后再次比较。如图:
这次立刻发生了失配,T下标又回溯到开始,S下标增1,然后再次比较。如图:
又一次发生了失配,所以T下标又回溯到开始,S下标增1,然后再次比较。这次T中的所有字符都和S中相应的字符匹配了。函数返回T在S中的起始下标3。如图:
二. KMP匹配算法
利用前面比较的结果,得出一个next数组或nextval数组(后者是前者的改良版),此数组的值为j的回溯值。即KMP算法回溯的是j,不是i。
1 next数组的求法:
1.1 理解思路:a 当 j=1,next[ j]=0 ;
b 当 j=j,时,得到模式串的0---(j-1)的子串,求的该子串的前缀与后缀的最长公共串,则next[ j]=最长公共串+1;
c 其它情况,next[
j ]=1 ;
例 如: T=“a b a b a a a b a”
j 1 2 3 4 5 6 7 8 9
next [ j ] 0 1 1 2 3 4 2 2 3
当j=6时,得到T的1--5的子串ababa,则ababa 的前缀为:a,ab,aba,abab
的后缀为:baba,aba,ba,a
前缀与后缀的最长公共串为aba,则next[ 6]=3+1=4
1.2代码实现:
void get_next(String T,int *next){
int i,j;
i=1;
j=0;
next[1]=0;[b] [/b]
[b] while(i<T.length()){[/b]
if(j==0||T[i]==T[j]){ // T[ i]表示后缀的单个字符
++i; [b] // T[ j]表示前缀的单个字符[/b]
++j;
next[ i]=j;
}else{
j=next[ j]; // 若字符不相同,则j值回溯
}
}
}
2 nextval数组的求法:
当串的后面的字符都与首位的字符相等时,可以用首位的next[ 1 ]的值去取代与之相等的字符的netx[ j ]的值。
while(i<T.length()){
if(j==0||T[i]==T[j]){ // T[ i]表示后缀的单个字符
++i; // T[ j]表示前缀的单个字符
++j;
next[ i]=j;
if(T[ i]!=T[j])
nextval[ i]=j; // 当前字符与前缀字符不同,则当前的j为nextval在i位置的值
else
nextval[ i]= nextval[ j] //若相同,则将前缀字符的nextval值付给nextval在i位置的值
}else{
j=next[ j]; // 若字符不相同,则j值回溯
}
}
3 KMP算法 ([b]KMP算法回溯的是j,不是i。)[/b]
while(i<s.length&&j<t.length){if(j==0||s[ i]==t[ j]){
++i;
==j;
}else{
j=next[ j]; // j=nextval[ j]; j退回到合适的位置,i值不变
}
}
参考:
http://blog.csdn.net/niushuai666/article/details/6960985
相关文章推荐
- 实现KMP算法的几种理解方法
- KMP算法的一次理解
- 详解KMP算法,理解并记忆KMP
- 我所理解的KMP算法
- 帮你理解KMP算法以及怎么求next数组
- 教你从头到尾彻底理解KMP算法
- 理解和实现KMP算法
- 彻底理解KMP算法
- 【转】kmp算法的理解与实现
- Kmp算法的比较好理解的博文···
- 通俗理解KMP算法
- KMP算法理解
- 数据结构笔记--通过与BF算法的比较理解KMP算法
- 从头到尾理解KMP算法
- 字符串匹配:KMP算法, Boyer-Moore算法理解与总结
- 深入理解KMP算法
- 超级简单的理解kmp算法中的next的计算
- KMP算法 --- 深入理解next数组
- KMP算法 一般详解,NEXT数组 一般理解 k = next[k] ——综合转载
- KMP算法最浅显理解——一看就明白