KMP实现
2015-09-11 17:00
218 查看
代码
Version 1/* The length of p(attern) is len, the length of next array is (len+1). */ void preKMP_one(char *p, int *next, int len){ int i = 0, j = -1; next[0] = -1; while (i < len){ while(j >= 0 && p[i] != p[j]) j = next[j]; i++; j++; next[i] = j; } }
Version 2
/* The length of p(attern) is len, the length of next array is (n+1). */ void preKMP_two(const char *p, int *next, int len){ next[0] = next[1] = 0; for(int i = 1; i < len; i++){ int j = next[i]; while(j != 0 && p[j] != p[i]) j = next[j]; if(p[i] == p[j]) next[i+1] = j+1; else next[i+1] = j; // /***The same as*** if(p[i] == p[j]) next[i+1] = j+1; else next[i+1] = 0; // Note that j == 0 under this condition. ***/ // Also the same as // next[i+1] = p[i] == p[j] ? j+1:j; // or next[i+1] = p[i] == p[j] ? j+1:0; } }
比较
跳转表(next数组)长度为n+1,跳转表最后一项,表示当该pattern匹配完全后,继续匹配时需要从pattern的哪个位置开始匹配,这一项对于需要连续查找匹配的情况很方便;两者都是计算next表下一项的值(相对于内部while循环时的i);
1中由于内部的while循环之后,不做判断(j是否为0),直接进行i++,j++,因此需要设置next[0]==-1防止死循环(j = next[j] -> 0 = 0)
从上一条可以看出,若将1中内部while循环之后的语句(i++;j++;next[i]=j)改为条件判断然后赋值,则1和2将几乎相同;
本质上,内部的while循环跳出的条件有两个: j 和 p[i] == p[j]。当p[i] == p[j]时,p[i+1] == j+1;而当P[i] != pj时,则p[i+1] = 0(此时1中的j=-1,2中的j=0)。
next的意义:当出现text[j] != p[i]时,下一次的比较应该在text[j]和p[next[i]]之间进行。next[i]表示p[i]的前缀(p[0..i-1])中头和尾相等部分的长度,即,设next[i] = k,则p[0..k-1] = p[i-j..i-1]。比如next[3] = 1,则p[0] == p[2]。
优化
可进行优化如下(以Version 1为例)Version 3
/* The length of p(attern) is len, the length of next array is (len+1). */ void preKMP_three(char *p, int *next, int len){ int i = 0, j = -1; next[0] = -1; while (i < len){ while(j >= 0 && p[i] != p[j]) j = next[j]; i++; j++; // optimization if (p[i] == p[j]) next[i] = next[j]; else next[i] = j; } }
注意:
该版本中,计算至最后,p的下标实际上会越界(12行if条件的判断中),但此时i=len, p[len]的值为’\0’,因此并不会产生错误,但需要注意;
该版本的next数组中可能会有很多的-1(除next[0]外),这些-1表示:直接比较text中下一个字符(text[j+1])和p[0],而非非优化版中的继续比较text[j]和p[next[i]]。
KMP-Match
int kmp(const char *text, int tlen, const char *p, int plen) { int *next = new int[plen+1]; if(!next) return -1; //preKMP_one(p, next, plen); preKMP_three(p, next, plen); int i = 0, j = 0; while(i < tlen && j < plen){ if(j == -1 || text[i] == p[j]) i++, j++; else j = next[j]; } delete [] next; if (j >= plen) return i-plen; else return -1; }
KMP for Version 2
int kmp(const char *text, int tlen, const char *p, int plen) { int *next = new int[plen+1]; if(!next) return -1; preKMP_two(p, next, plen); int i = 0, j = 0; while(i < tlen && j < plen){ if(!j || text[i] == p[j]) i++, j++; else j = next[j]; } delete [] next; if (j >= plen) return i-plen; else return -1; }
相关文章推荐
- 数据结构之自建算法库——单链表
- 内测首日笔记
- Java编程思想:第6章 访问权限控制
- java线程的suspend()、stop()方法废弃原因
- mysql file sort
- 算法——动态规划
- 一种高效无锁内存队列的实现
- Codeforces Round #319 (Div. 2) ——C. Vasya and Petya's Game(数学题)
- 格式验证非正则表达式方法
- Android中SQLite应用详解
- 一个JAVA数据库连接池源码实现(转)
- 面试题——分析从输入url到页面返回的过程(或者查询返回过程)
- 常见导航条的实现
- Android中SQLite应用详解
- stuct、class、typedef
- flam3 ubuntu 依赖文件
- JQ实现accordion(可折叠)效果
- Storm日志分析调研及其实时架构
- 排序1
- RHEL 7 安装oracle rac 11.2.0.4执行root.sh报错ohasd failed to start