KMP算法简介及代码实现
2013-12-01 21:18
357 查看
前提 :
假设我们在字符串 “bacbababaab[b][b][b][b][b][b][b]ababca[/b][/b][/b][/b][/b][/b][/b]”中搜寻字符串 “abababca”是否存
在。下面就KMP算法的匹配过程进行阐述。
step0 :在执行匹配之前,先定义几个概念:“前缀集合","后缀集合","部分匹配值"
"前缀集合"指除了最后一个字符外,一个字符串的全部头部组合;
"后缀集合"指除了第一个字符外,一个字符串的全部尾部组合。
"部分匹配值"指"前缀集合"与"后缀集合"的最长公共元素的长度
1. 举个例子,如字符串 “a”,前缀集合用prefixes表示 (下同),按照定义
除了最后一个字符,则为空,所以prefixes={},后缀集合用suffixes表示(下同),按照定义除了第
一个字符也为空,即suffixes={},所以集合 prefixes与 suffixes交集也为空,两个集合的公共元素
的长度(即部分匹配值)为0,我们称"a"的部分匹配值为0
2. 再比如字符串 “abab”,则prefixes = {"a","ab","aba"},suffixes={"b","ab","bab"},则前缀集合与后缀集
合的交集:{ ”ab“} ,长度为2,即"abab"的部分匹配值为2
3.有些字符串比较特别如 "ababa",其prefixes={"a","ab","aba","abab"},
suffixes={"a","ba","aba","baba"},这时候prefixes与suffixes的交集就变成了
{"a","aba"},公共元素有两个,这个时候部分匹配值我们取最大的元
素"aba",长度为3
这样我们就能得到字符串“abababca”的部分匹配表
char: | a | b | a | b | a | b | c | a | index: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | value: | 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 |
下面开始KMP算法的字符串匹配过程
step1 : 首先从第一位进行字符串比较 bacbababaab[b][b][b][b][b][b][b][b]ababca[/b][/b][/b][/b][/b][/b][/b][/b]
[b]
abababca[/b]
可以看到b 与a 并不相等,此时我们直接后移一位
step2 : 第三个字符“c”时候不匹配 bacbababaab[b][b][b][b][b][b][b][b]ababca[/b][/b][/b][/b][/b][/b][/b][/b]
[b] abababca[/b]
这个时候已经匹配了字符“a”,按照部分匹配表,其部分匹配值为0
,这个时候
后移动位数=
已经匹配的字符数-已经匹配的字符对应的部分匹配值
= 1 - 0 = 1
step3 :而移动后的bacbababaab[b][b][b][b][b][b][b][b]ababca[b][b]ababca[/b][/b][b][b]ababca[/b][b]ababca[/b][/b][/b][/b][/b][/b][/b][/b][/b][/b]
[b][b]abababca[/b][/b]
c与a 又不相等,继续移动 直到
step4
:bacbababaab[b][b][b][b][b][b][b][b]ababca[/b][/b][/b][/b][/b][/b][/b][/b]
[b][b][b]abababca[/b][/b][/b]
[b][b][b]
这次的匹配直到a 与b字符不相等,这个时候已经匹配的字符为“ababa”,长[/b][/b][/b]
[b][b][b]
度为[/b][/b][/b]5,“ababa”对应的部分匹配值通过查表为3
后移位数= 已经匹配的字符数-已经匹配字符对应的部分匹配值
= 5-3 = 2
step5 : 移动后 得到 bacbababaab[b][b][b][b][b][b][b][b]ababca[/b][/b][/b][/b][/b][/b][/b][/b]
[b][b][b]abababca[/b][/b][/b]
这个时候 后移位数 = 3-1 =2
step6 : 再次移动后 bacbababaab[b][b][b][b][b][b][b]ababca[/b][/b][/b][/b][/b][/b][/b]
[b][b][b]abababca[/b][/b][/b]
[b][b][b]
只匹配了a之后又不匹配,则按照匹配表又往后移动一位[/b][/b][/b]
[b][b][b][b]step7
: 这个时候:bacbababaab[b][b][b][b][b][b][b]ababca[/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b]
[b][b][b]abababca[/b][/b][/b]
[b][b][b]
发现字符串全部匹配,至此匹配结束[/b][/b][/b]
[b][b][b]
总结 : 如果字符串发生了匹配,那么根据部分匹配表进行的后移之后一定会让[/b][/b][/b]
[b][b][b]
字符串的首字母再匹配(有可能会从首字母开始匹配多个),后移位数[/b][/b][/b]
[b][b][b]
完全取决于查找的字符串,跟需要被查找的字符串没有关联。[/b][/b][/b]
[b][b][b]
下面附上 KMP算法的java代码实行[/b][/b][/b]
[b][/b]
package com.util; import org.apache.log4j.Logger; /** * @author ycx * */ public class KMPStringMatcher { private static final Logger logger = Logger .getLogger(KMPStringMatcher.class); private char[] targetArr = null; private char[] sourceArr = null; private int[][] partionMatchTable = null; private static final int NOT_MATCH = -1; public static void main(String[] args) { String target = "BBC ABCDAB ABCABCDABDDABCDABDE"; String match = "ABCDABD"; KMPStringMatcher kmp = new KMPStringMatcher(target); System.out.println(kmp.find(match)); } /** * 构造器 * * @param targetStr */ public KMPStringMatcher(String targetStr) { if (targetStr == null) throw new NullPointerException("target string can not be null"); this.targetArr = targetStr.toCharArray(); } /**KMP算法匹配字符串的入口函数 * @param match * @return */ public synchronized int find(String match) { if (match == null) throw new NullPointerException("match string can not be null"); char[] matchArr = match.toCharArray(); if (sourceArr == null || !isTwoCharArrEqual(sourceArr, matchArr)) { calculatePartionMatchTable(matchArr); sourceArr = matchArr; } if (targetArr.length < sourceArr.length) return NOT_MATCH; return getFirstPartionMatched(matchArr); } /**返回完全匹配的第一个字符位置 * @param matchArr * @return */ private int getFirstPartionMatched(char[] matchArr) { int i = 0, j = 0, moveStep = 0; int firstPartion = NOT_MATCH; while (j < matchArr.length && i < targetArr.length) { if (matchArr[j++] != targetArr[i++]) { moveStep = (j == 1) ? 1 : (j - 1 - partionMatchTable[1][j - 2]); //后移位数 i = i -j + moveStep; j = 0; continue; } if (j == matchArr.length) { firstPartion = i - j; break; } } return firstPartion; } /**计算部分匹配表:算法的关键 * * @param matcherString * @return */ private boolean calculatePartionMatchTable(char[] match) { partionMatchTable = new int[2][match.length]; partionMatchTable[0][0] = 0; partionMatchTable[0][1] = 0; int length = 0; char[] a, b; for (int i = 1; i < match.length; i++) { length = 0; for (int j = 0; j < i; j++) { a = getSubArr(match, 0, j); b = getSubArr(match, i - j, i); if (isTwoCharArrEqual(a, b)) length = (a.length > length) ? a.length : length; } partionMatchTable[0][i] = i; partionMatchTable[1][i] = length; } return true; } /** 从一个字符数组中提取从 start 开始到 end 结束的子数组 * @param target * @param start * @param end * @return */ public static char[] getSubArr(char[] target, int start, int end) { if (target == null || start < 0 || end >= target.length) { return null; } if (target == null || target.length == 0) throw new NullPointerException(); char[] charArr = new char[end - start + 1]; int count = start; int targetCount = start; while (count <= end) charArr[(count++) - start] = target[targetCount++]; return charArr; } /** 判断两个字符数组是否equal :基于数组元素判断 * @param from * @param to * @return */ public static boolean isTwoCharArrEqual(char[] from ,char[] to){ if(from == null || to == null) return false ; if(from.length != to.length) return false ; int i = 0; int j = 0; int count =0; while(from[i++] == to[j++]){ ++count ; if(i >= from.length) break; } return (count == from.length)?true:false; } /**替换被匹配的目标文本 * @param replaceStr * @return */ public synchronized boolean replaceTheTargetStr(String replaceStr){ if(replaceStr == null || replaceStr.equals("")) throw new NullPointerException(); this.targetArr = replaceStr.toCharArray(); return true ; } }
相关文章推荐
- 【杂谈】【转载】卡尔曼滤波简介及其算法实现代码
- 数据结构 - 队列简介 及 1个简单的c语言链式队列代码实现
- kmp算法的c代码实现
- MD5的简介以及实现其算法原理的各种语言的代码
- MD5简介与代码实现
- KMP算法与next数组的代码初步实现
- 【杂谈】【转载】卡尔曼滤波简介及其算法实现代码
- 卡尔曼滤波简介及算法实现代码
- 基于JQuery的Swiper插件实现移动手机端幻灯片切换(可在每一张幻灯片div中插入自定义的元素,代码简介,扩展性好。)
- MD5简介以及java代码实现
- 卡尔曼滤波简介及其算法实现代码(C++/C/MATLAB)
- base64简介与代码实现
- moravec、harris、Shi-Tomasi角点检测的简介及OpenCV代码实现
- 7、KMP算法实现--Java代码
- 卡尔曼滤波简介及其算法实现代码(C++/C/MATLAB)
- KMP算法的C++实现代码
- 卡尔曼滤波简介及其算法实现代码(C++/C/MATLAB)
- 决策树简介及代码实现
- 设计模式之工厂模式简介与代码实现