写本文的目的:

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. 洛谷P2973 [USACO10HOL]赶小猪(高斯消元 期望)

    题意 题目链接 Sol 设\(f[i]\)表示炸弹到达\(i\)这个点的概率,转移的时候考虑从哪个点转移而来 \(f[i] = \sum_{\frac{f(j) * (1 - \frac{p}{q}) ...

  2. 爬虫必备—Scrapy

    一.Scrapy简介 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓取 ...

  3. spring shiro 集成

    1.向spring项目中添加shiro相关的依赖 <dependency> <groupId>commons-logging</groupId> <artif ...

  4. mybatis大于小于的转义

    最近在使用mybatis,然后用到了小于等于,直接在XML中使用了<=,结果XML文件一直显示红色错误,如下: sum(case when p.pool_year <= '2014' th ...

  5. Excel连接字符串在.NET中的应用

    转:https://www.cnblogs.com/jaxu/archive/2011/07/29/2121022.html 介绍几种在.NET中直接连接Excel作为数据源的几种方法以及连接字符串的 ...

  6. WWF3.5SP1 参考源码索引

    http://www.projky.com/dotnet/WF3.5SP1/System/Runtime/Serialization/FormatterServicesNoSerializableCh ...

  7. 从MySQL向Greenplum集群中导入数据

    我们要从MySQL当中导出数据到Greenplum当中,按照以下步骤就可以 1:将MySQL当中的表导出外部文件 以schema_name.table_name为例 select product_id ...

  8. Javascript---add to favorite | Set Homepage

    <!-- 设为首页 --> <li><a href="javascript:setHome(this,window.location)"> &l ...

  9. JavaWeb定时器-Spring3.x及更高版本Task使用

    大背景 现代的 Web 应用程序框架在范围和复杂性方面都有所发展,应用程序的每个底层组件也必须相应地发展.作业调度是现代系统中对 Java 应用程序的一般要求,而且也是对 Java 开发人员一贯的要求 ...

  10. 《C++ Primer Plus》读书笔记之十—类和动态内存分配

    第12章 类和动态内存分配 1.不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存.可以在类声明之外使用单独的语句进行初始化,这是因为静态类成员是单独存储的,而不是对象的 ...