本文主要介绍KMP算法原理。KMP算法是一种高效的字符串匹配算法,通过对源串进行一次遍历即可完成对字符串的匹配。

1、基础知识的铺垫

字符串T的前k(0 =< k <=tlen)个连续的字符串称为T的前缀(假如T的长度为tlen),则当k<tlen时,其前缀称为真前缀。同理,字符串T的后k个连续的字符串称为T的后缀,k<tlen时其后缀称为真后缀。

假如现在有字符串str=”abbaba”。则该字符串的真前缀有:a, ab, abb, abba, abbab. 其真后缀有:a, ba, aba, baba, bbaba。前缀包括源字符串本身,但真前缀不包括,后缀也一样。空字符串是任何字符串的前缀和后缀。

2、前缀函数next的计算

若一个字符串的真前缀等于后缀,我们称它为相等前后缀(为了表达方便,就用相等前后缀表示前后缀相等的前缀,这是本人取得名字,非专业术语)。

前缀函数next的计算就是计算最大相等前后缀的长度。比如字符串p=”ababaca”中,p[3]的最大相等前后缀为ab。next[3]=len(“ab”)=2。对字符串中每个字符计算next就可以得到一个next数组。

那么如何计算next数组呢?假如现在需要计算p[i]的next值,即next[i]。在计算next[i]时,前面的next[0]~next[i-1]已经计算了出来,这时,其计算过程如下:

令k=next[i-1]。若k>0&& p[i]!=p[k]。则k=next[k-1]。因为数组的下标是从0开始的,所以在比较时使用p[i]与p[k] 比较而不是p[k+1],而在重新获取k的值时,使用next[k-1],因为next数组是从0开始的,并且字符串数组也是从0开始计数的,书本上介绍的基本都是从1开始计数的,这是本文与书本之间存在的一点小小区别,但核心思想一样。

关于这点,更通俗的说法是:在计算next[i]时,因为前面的next[i-1]指出了前i-1个字符串的最大相等前后缀。为了计算字符串p[i]的最大相等前后缀的长度,若字符串p[0,1,…, i-1]的最大相等前后缀为p[0,1,…, k-1](k=next[i-1])。此时若p[k]==p[i],则next[i]=k+1。因为这时p[0,1,…, k]==p[i-k, i-k+1, …, i]。

若p[k]!=p[i],为区别起见,我们用q=next[k-1]。如下图所示,此时比较p[i]与p[q]即p[next[k-1]]。因为p[0, 1, .., k-1]==p[i-k, i-k+1,…, i-1],p[0, 1,…, q-1 ] == p[k-q, k-q+1, .., k-1]。若此时p[i] == p[q],则p[i]的最大相等前后缀的长度next[i] = q+1。否则, 如果p[i]!=p[q],则重复此过程,直到q=0。

关于前缀函数的正确性,算法导论有详细的证明,在此略过。

其前缀函数源代码如下:

int *getprefix(char p[])
{
int *h, plen, k, i;
plen = strlen(p);
h = (int *)malloc(plen*sizeof(int));
h[0] = 0;
k=0;
for(i=1; i<plen; i++)
{
while(k>0 && p[k]!=p[i])
k=h[k-1];
if(p[k] == p[i])
k++;
h[i]=k;
}
return h;
}

3、KMP匹配算法的实现

在计算好前缀数组next之后,就可以开始对源字符串进行比对,从源字符串的第0个到最后一个依次进行遍历。这个过程类似计算next数组。只是计算前缀函数的时候是自己与自己进行比较,对每个源串中的字符,若模式串中相应的字符与之不相等,则根据next数组确定模式串中下一个进行比较的字符。

若源串中的字符与模式串中相应的字符相等,则对两个串中的下一个字符进行比较,依次对源串进行一次遍历。

若有模式串匹配成功,则根据next数组将模式串的位置移动指定地方,继续进行比对。

KMP匹配代码如下:

int kmp_matcher(char t[], char p[])		//返回源串中模式串出现的次数
{
int count;
int *h, tlen, plen, i, q;
tlen = strlen(t);
plen = strlen(p);
h = getprefix(p);
count = 0;
q=0;
for(i=0; i<tlen; i++)
{
while(q>0 && t[i]!=p[q])
q = h[q-1];
if(t[i] == p[q])
q++;
if(plen == q)
{
count++;
q = h[q-1];
}
}
return count;
}

KMP算法深入解析的更多相关文章

  1. 不能更通俗了!KMP算法实现解析

    我之前对于KMP算法理解的也不是很到位,如果很长时间不写KMP的话,代码就记不清了,今天刷leetcode的时候突然决定干脆把它彻底总结一下,这样即便以后忘记了也好查看.所以就有了这篇文章. 本文在于 ...

  2. 【原创】通俗易懂的讲解KMP算法(字符串匹配算法)及代码实现

    一.本文简介 本文的目的是简单明了的讲解KMP算法的思想及实现过程. 网上的文章的确有些杂乱,有的过浅,有的太深,希望本文对初学者是非常友好的. 其实KMP算法有一些改良版,这些是在理解KMP核心思想 ...

  3. KMP算法详解-彻底清楚了(转载+部分原创)

    引言 KMP算法指的是字符串模式匹配算法,问题是:在主串T中找到第一次出现完整子串P时的起始位置.该算法是三位大牛:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的,以其名字首字 ...

  4. KMP算法解析(转自图灵社区)

    KMP算法是一个很精妙的字符串算法,个人认为这个算法十分符合编程美学:十分简洁,而又极难理解.笔者算法学的很烂,所以接触到这个算法的时候也是一头雾水,去网上看各种帖子,发现写着各种KMP算法详解的转载 ...

  5. KMP算法解析

    介绍一种高效的KMP算法:代码可以直接运行 #include <iostream> #include <iomanip> using namespace std; void p ...

  6. poj_3461 KMP算法解析

    A - Oulipo Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit S ...

  7. Java数据结构之字符串模式匹配算法---KMP算法

    本文主要的思路都是参考http://kb.cnblogs.com/page/176818/ 如有冒犯请告知,多谢. 一.KMP算法 KMP算法可以在O(n+m)的时间数量级上完成串的模式匹配操作,其基 ...

  8. 字符串匹配的KMP算法详解及C#实现

    字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...

  9. KMP算法具体解释(转)

    作者:July. 出处:http://blog.csdn.net/v_JULY_v/. 引记 此前一天,一位MS的朋友邀我一起去与他讨论高速排序,红黑树,字典树,B树.后缀树,包含KMP算法,只有在解 ...

随机推荐

  1. oracle数据库查询常用语句

    1.查询SCOTT表中有多少表,并显示表的一些描述select * from all_tables WHERE owner='SCOTT' ; 2.查询oracle数据库版本select * from ...

  2. hrbustoj 2013 Play Game 2(博弈)

    注释在代码里 /* 1.若输入2 ~ 9 ,因为Stan 是先手,所以Stan 必胜 2.若输入10~18 ,因为Ollie 是后手,不管第一次Stan 乘的是什么,Stan肯定在 2 ~ 9 之间, ...

  3. fragment 数据传递,通信

    Fragment之间的通信   在本节中,你会学到 1.定义接口 2.实现接口 3.将消息传递给fragment 为了重用Fragment UI 组件,在设计中你应该通过定义每一个fragemnt自己 ...

  4. CvvImage类

    从OpenCV 2.2.0开始,OpenCV取消了CvvImage这个类.可是今天要用到,可以自己加入到工程中. 首先,找到CvvImage的原代码.我在网上已经找到了,具体代码如下. 这是CvvIm ...

  5. LINQ to SQL语句对应SQL的实现

    LINQ to SQL语句(1)之Where LINQ to SQL语句(2)之Select/Distinct LINQ to SQL语句(3)之Count/Sum/Min/Max/Avg LINQ ...

  6. ural1890 Money out of Thin Air

    Money out of Thin Air Time limit: 1.0 secondMemory limit: 64 MB Each employee of the company Oceanic ...

  7. openssl使用+Demo

    1. websiteSSL(secure Socket Layer)TLS(transport Layer Security) - SSL3.0基础之上提出的安全通信标准,目前版本是1.0openss ...

  8. LVS详解

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  9. CodeForces 617A Elephant

    C语言语法入门题 #include<cstdio> #include<cstring> #include<vector> #include<cmath> ...

  10. 使用for循环运算

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...