一.理论基础
1.什么是kmp算法
同BF算法一样,就是串的模式匹配算法。
前面已经学过,我想都应该明白BF算法,就是用一种最直观的方式进行模式匹配。
优点:非常容易理解,是我们常用的思维方式来编程;
缺点:效率比较低,在匹配不成功的时候,回朔做了许多无用功;
从而根据其缺点,KMP算法就在回朔的时候做了工作,减少其无用功,那么怎么去减少回朔的工作呢?
下面举例说明:
例如:
s = abababc
t = ababc
其匹配过程如下图:
从图中我们看到了具体的变换过程,就是在回朔的过程中做了许多工作,S的i不需要回朔到1,只需要T回朔就可以了,那么怎么知道T回朔到什么位置才好呢?而从上面的图中我们也会发现,其实回朔跟S串是没有关系的,i压根就没变,变的是T的j,故而需要回朔的是T--待匹配模式串,所有回朔的位置是由T串的特点决定的!!当然,就这是问题2,求next数组。
2.为什么要求next数组
什么是next数组,简而言之,就是当不匹配的时候,从当前j的位置需要回朔的位置k
如上面的图中,当j=4的时候,回朔的位置是2,故而next[4]=2,这就是next的价值所在:决定在位置j不匹配的时候,回退到位置next[j].
3.next如何求之理论基础
既然求next完全是T的事,那么我这里就不像那些书上那样从S去分析,直接切入正题从T分析!书上有时候说的反而有碍思维,要是完全照书,我就不写这些了!
首先实例分析:
2。代码
#include <iostream>
using namespace std;
int strLen(const char *s){
if(!s) throw "串不能为空!\n";
int i=0;
while(*s != '\0'){
i++;
s++;
}
return i;
}
/**
*求next数组值
*求模式t的next值并存入next数组中
*t :待求模式数组
*n :模式数组长度
*next:next数组
*/
void getNext(const char* t, int n, int* next){
int i=0, j=-1;
next[0] = -1;
while(i < n){
//如果j==-1,则回退到了开始位置(只有当开始的时候j才为-1,only one,以后至少都是0)
//如果相等,匹配,故而向前,此时i的next的值就是j,且存的是最大的j
if(j == -1 || t[j] == t[i]){
i++;
j++;
next[i]=j;
}else{//如果不等或j为其他,则j回到next[j]位置继续匹配
j = next[j];
}
}
}
//1.Brute-Force算法(BF算法)
//子串定位(p若属于s,返回串p在s中的位置,否则返回0)
int strIndex(const char* s, const char* p){
if(!s || !p) throw "串不能为空!\n";
int i=0, j=0, r = 1;
int sl = strLen(s);
int pl = strLen(p);
if(sl < pl) throw "参数异常,串长度!\n";
while(i<sl && j<pl){
if(s[i] == p[j]){
i++; j++;
}else{//恢复开始的位置的下一个位置
i = i-j+1;
j = 0;
}
}
if(j >= pl) r = i-pl+1;
else r = -1;
return r;
}
//2.KMP算法
//具体的讲解,见博文
int strIndex_kmp(const char* s, const char* p){
if(!s || !p) throw "串不能为空!\n";
int i=0, j=0, r = 1;
int sl = strLen(s);
int pl = strLen(p);
if(sl < pl) throw "参数异常,串长度!\n";
//求next
int *next = new int[pl];
getNext(p, pl, next);
cout<<"next数组:";
for(int j=0; j<pl; j++){
cout<<next[j]<<" ";
}
cout<<endl;
while(i<sl && j<pl){
if(j==-1 || s[i] == p[j]){
i++; j++;
}else{//恢复到next[j]
j = next[j];
}
}
if(j >= pl) r = i-pl+1;
else r = -1;
delete next;
return r;
}
int main(){
//char a[] = {'a','c','a','b','a','a','b','a','a','b','c','a','c','a','a','b','c','\0'};
//char b[] = {'a','b','a','a','b','c','\0'};
char a[] = {'a','b','a','b','a','b','c','\0'};
char b[] = {'a','b','a','b','c','\0'};
try{
cout<<"BF算法:"<<strIndex(a ,b)<<endl;
cout<<"KMP算法:"<<strIndex_kmp(a, b)<<endl;
}catch(const char* s){
cout<<s<<endl;
}
}
- 大小: 29.4 KB
- 大小: 53 KB
分享到:
相关推荐
#资源达人分享计划#
kmp算法
KMP算法精解,由浅入深,层层递进,深度解析KMP算法的实现。
六、教你从头到尾彻底理解KMP 算法 七、遗传算法 透析GA 本质 八、再谈启发式搜索算法 九、图像特征提取与匹配之SIFT 算法 九(续)、sift 算法的编译与实现 九(再续)、教你一步一步用c 语言实现sift 算法、上九...
六、教你初步了解KMP算法、updated (KMP算法系列三篇文章) 六(续)、从KMP算法一步一步谈到BM算法 六(三续)、KMP算法之总结篇(必懂KMP) 七、遗传算法 透析GA本质 八、再谈启发式搜索算法 九、图像特征提取...
一大堆模版 自己可以下来参考 应该有200个以上吧 自己下来看看 ... KMP Trie结构 后缀树/后缀数组 LCA/RMQ 有限状态自动机理论 排序 选择/冒泡 快速排序 堆排序 归并排序(OK) 基数排序 拓扑排序 排序网络
LINUX日常代码集锦,dns 数据包解析,kmp 算法 c 语言实现
蛮力法解决0/1背包问题(轻松理解) 另有文档详细解析 还顺带写了KMP算法
经典题目解析&golang版代码 简单难度 中等难度 困难难度 算法专项 KMP 算法 动态规划: 887. 鸡蛋掉落 5. 最长回文子串 494. 目标和 322. 零钱兑换 279. 完全平方数 198. 打家劫舍 152. 乘积最大子序列 139. 单词拆分...
4.2.3 KMP 算法的改进 99 习题 102 习题答案 103 5 章 数组、矩阵与广义表 113 知识点讲解 113 5.1 数组 113 5.2 矩阵的压缩存储 114 5.2.1 矩阵 114 5.2.2 特殊矩阵和稀疏矩阵 115 5.3 广义表 121 习题 122 习题...
底层的实现原理采取的是AC自动机算法,AC自动机是在KMP算法和字典树上演变出来的一种多模匹配的算法。时间复杂度只取决于待分析文本的长度,和敏感词的数量无关。 有兴趣的小伙伴可以阅读关于KMP 和 AC自动机相关...
字符串KMP算法 BitSet解决数据重复和是否存在等问题 哈希算法 一致性哈希算法? 1.1.2 Java语法糖 string的hash算法 hash冲突的解决办法:拉链法 foreach循环的原理 volatile关键字的底层实现原理 泛型类 泛型接口 ...
实现KMP算法 问题 30 连接所有单词的子串 提高效率,现在使用 DFS 问题 35 搜索插入位置 搞清楚原理 问题 44 通配符匹配 实施自下而上的动态规划,目前超过 54%/20% 问题 45 跳跃游戏 II 实施,目前超过 14%/36% ...