写本文的目的:

1.加深自己的理解,以便自己日后复习

2.给看到此文的人一点启发

KMP算法看懂了就觉得特别简单,思路也好理解,但是看不懂之前,查各种资料看大佬的博客,都很懵逼......

1.  算法过程解释

首先,字符串"BBCABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。

就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。

接着比较字符串和搜索词的下一个字符,还是相同。

直到字符串有一个字符,与搜索词对应的字符不相同为止。

这时,最自然的反应是,将搜索词整体后移一位,即从上图B处再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把搜索的初始位置移到已经比较过的位置,重比一遍。

一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,此时不只移动一位,移动数是已经比较的字符数 - 最后一个匹配字符所对应的部分匹配值,这个部分匹配值实质上就是字符串头部和尾部重复部分的最大长度。因此就有了部分匹配值数组:

已知空格与D不匹配时,前面六个字符"ABCDAB"是匹配的。查表可知,最后一个匹配字符B对应的"部分匹配值"为2,因此向后移动的位数为已匹配的字符数减去对应的部分匹配值,即6-2=4。

因为空格与C不匹配,搜索词还要继续往后移。这时已匹配的字符数为2("AB"),最后一个匹配字符B对应的"部分匹配值"为0。所以,移动位数为 2,于是将搜索词向后移2位。

因为空格与A不匹配,继续后移一位。

逐位比较,直到发现C与D不匹配。于是,移动位数为 6 - 2,继续将搜索词向后移动4位。

逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。如果需要找出全部的匹配,移动位数为7 - 0,再将搜索词向后移动7位,剩下的操作就重复了。

首先,要了解两个概念:前缀和后缀。

"前缀"指除了最后一个字符以外,一个字符串的全部头部组合;

"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。

"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例:


  1. "A"的前缀和后缀都为空集,共有元素的长度为0;
  2. "AB"的前缀为[A],后缀为[B],共有元素的长度为0;
  3. "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
  4. "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
  5. "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;
  6. "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;
  7. "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。

KMP算法的核心思想(个人理解):根据子串确定每次匹配失败的时候主串开始比较位向前移动的位数,位数=已经比较的字符数 - 最后一个匹配字符所对应的部分匹配值,这个就是KMP和暴力匹配算法的根本区别

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
void getnext(char a[],int l,int next[])
{
//a字符串数组为子串,l为字符串a的长度,next为a的匹配值数组
int j;
int k=;
next[]=;//初始化
j=;
while(j<=l-)
{
if(k==)//a[0]和a[x]比较
{
if(a[k]==a[j])
{ k++;//k向后移动一位
next[j]=k;
j++;
}else
{
//k不动
next[j]=k;
j++;
}
}
if(k!=)//k此时不在a[0]的位置上
{
if(a[k]==a[j])
{
k++;//k后移一位
next[j]=k;
j++;//j后移一位
}
else
{
k=;//k重新回到a[0]
}
}
}
}
void KMP(char str[],char a[])
{
int L=strlen(str);//字符串长度
int l=strlen(a);
int i,j;
i=j=;
int next[l];
getnext(a,l,next);//活动匹配值数组
int sum=;//匹配成功的次数
while(i<=L&&j<=l)
{
if(str[i]==a[j]&&j==)//匹配中的四种情况
{
i++;
j++;
}else if(str[i]==a[j]&&j!=)
{
i++;
j++;
}else if(str[i]!=a[j]&&j==)
{
j=;
i++;
}else if(str[i]!=a[j]&&j!=)
{
int s=j-next[j-];
i=i-j+s;
j=;
}
if(j==l)//匹配成功的条件
{
printf("第%d此成功匹配的位置为:%d\n",sum,i-l);
sum++;
}
} }
int main()
{
char str[],a[];
gets(str);
gets(a);
KMP(str,a);
return ;
}

参考:

http://blog.csdn.net/seu_calvin/article/details/62232825

http://blog.csdn.net/starstar1992/article/details/54913261

不足错误之处欢迎拍砖!!!!!

KMP算法之从懵逼到入门的更多相关文章

  1. KMP算法——从入门到懵逼到了解

    本博文參考http://blog.csdn.net/v_july_v/article/details/7041827 关于其它字符串匹配算法见http://blog.csdn.net/WINCOL/a ...

  2. 【面向打野编程】——KMP算法入门

    一.问题 咱们先不管什么KMP,来看看怎么匹配两个字符串. 问题:给定两个字符串,求第二个字符串是否包含于第一个字符串中. 为了具体化,我们以 ABCAXABCABCABX 与 ABCABCABX为例 ...

  3. 【初识】KMP算法入门(转)

    感觉写的很好,尤其是底下的公式,易懂,链接:http://www.cnblogs.com/mypride/p/4950245.html 举个例子 模式串S:a s d a s d a s d f a  ...

  4. 【初识】KMP算法入门

    举个例子 模式串S:a s d a s d a s d f a s d 匹配串T:a s d a s d f 如果使用朴素匹配算法—— 1 2 3 4 5 6  8 9 a s d a s d a s ...

  5. KMP算法入门讲解

    字符串匹配问题.假设文本是一个长度为$n$的字符串$T$,模板是一个长度为$m$的字符串$P$,且$m\leq n$.需要求出模板在文本中的所有匹配点$i$,即满足$T[i]=P[0],T[I+1]= ...

  6. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  7. KMP算法的Next数组详解

    转载请注明来源,并包含相关链接. 网上有很多讲解KMP算法的博客,我就不浪费时间再写一份了.直接推荐一个当初我入门时看的博客吧:http://www.cnblogs.com/yjiyjige/p/32 ...

  8. 【转】KMP算法

    转载请注明来源,并包含相关链接.http://www.cnblogs.com/yjiyjige/p/3263858.html 网上有很多讲解KMP算法的博客,我就不浪费时间再写一份了.直接推荐一个当初 ...

  9. KMP算法的Next数组详解 转

    这个写的很好,还有讲kmp,值得一看. http://www.cnblogs.com/tangzhengyue/p/4315393.html 转载请注明来源,并包含相关链接. 网上有很多讲解KMP算法 ...

随机推荐

  1. javascript元素跟随鼠标在指定区域运动

    元素跟随鼠标在指定区域运动通常是用在商城图片的放大镜中,下面是完整的Demo: <!DOCTYPE html> <html lang="en"> <h ...

  2. vue2.0 element-ui中input的@keyup.native.enter='onQuery'回车查询刷新整个表单的解决办法

    项目中用的element-ui是v1.4.3版本 实现的功能是在input中输入查询的名称,按下键盘回车键,可以查询表格中数据 问题是,我输入名称,按下回车,会整个表单刷新,搜索条件也被清空:代码如下 ...

  3. Myeclipse打war包方法

    Myeclipse三种打包方法第一种方法打开Myeclipse如图操作. 如果该项目已存在需要移除之后在进行第三步,接着往下走. 项目打war包成功,推荐使用第一种方法. 第二种方法https://b ...

  4. CefSharp F12打开DevTools查看console

    winform嵌入chrome浏览器,修改项目属性 生成 平台为x86 1.nuget安装cefsharp 2.实例化浏览器 private void Form1_Load(object sender ...

  5. JavaSE——转换流和缓冲流

    转换流: 类 InputStreamReader(字符输入转换流): InputStream 即读取字节流,Reader 为读取字符流. InputStreamReader将字节流转换成字符流.便于一 ...

  6. Ubuntu加入opencv库的环境变量

    1.用gedit打开/etc/ld.so.conf 终端输入: sudo gedit /etc/ld.so.conf 文件末行加入:include /usr/loacal/lib .然后终端执行指令: ...

  7. Vue 框架-06-条件语句 v-if 实现选项卡效果

    Vue 框架-06-条件语句 v-if 实现选项卡效果 本片介绍的是 Vue 中条件语句 v-if 第一个小实例是,通过 v-if="布尔值",通过布尔值的真假来决定,某元素是否显 ...

  8. ORACLE学习文档

    转自 http://sparklet.blog.sohu.com/523655.html 数据库被分成一个或多个逻辑部件称作表空间.而表空间又被分成称作段(segment)的逻辑部件.这些段再细分就叫 ...

  9. redis介绍(7)高级用法

    redis的过期策略以及内存淘汰机制 分析:这个问题其实相当重要,到底redis有没用到家,这个问题就可以看出来.比如你redis只能存5G数据,可是你写了10G,那会删5G的数据.怎么删的,这个问题 ...

  10. [WSUS] [Windows 10 Upgrade 1607/1703] 升级出错,出现 0xC1800118 或者卡在下载中…… 0%后失败

    1. 安装 KB3159706 ,并进行安装后维护操作:https://support.microsoft.com/en-us/help/3159706/update-enables-esd-decr ...