本文主要介绍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. Suzuki EN3F 参数

  2. Ubuntu Linux系统下的SVN客户端工具PySVN

    在Windows下面一直在用TortoiseSVN做为SVN客户端工具,但它居然没提供Linux版本,无视Linux用户的存在.它视我如空 气,偶视它如废土.开始探索尝试其他跨平台的SVN客户端,最后 ...

  3. POJ 1062 昂贵的聘礼详解最短路变形

    POJ上难得一见的中文题…… 思路:建立一个以0为源点的地图,那么Map[0][n]的值代表 第n号物品的价值,Map[i][j]代表用 j  替代 i 后,物品j的价值.我们认为酋长的承诺为节点 ‘ ...

  4. Android程序两种退出的方法

    两种程序退出的方法: Context的finish()方法: android.os.Process的killProcess()方法:(当程序isRegistered()失败,说明程序被修改过,调用ki ...

  5. 读写锁的实现原理(pthread_rwlock_t)

    引言 不同的锁之间的语义是不一样的,没有一劳永逸的锁,只有更适合的锁. 如果是同一进程里的不同线程共享读写锁,那么读写锁变量的维护是在进程内部即可.如果是不同进程共享读写锁,那么读写锁变量的维护是在共 ...

  6. kindeditor集成ckplayer(带右键编辑菜单)

    相信好多朋友为开源web编辑器没有集成视频播放器而烦恼,于是我就是试着修改了一下kindeditor,其实ueditor应该也是同样的,好了不多说了直接上图吧 kindeditor版本: 4.1.7  ...

  7. PS2鼠标+LCD12864实验——终于OK 了

    抱着“不气馁.不放弃.誓不罢休.搞不定你我还能搞其他玩意吗”的心态,调试许久的PS2鼠标实验,终于在今天被我搞定了.发几张图显摆一下,嘿嘿...    左键按下+鼠标移动 右键按下+鼠标移动  中键按 ...

  8. Ketama Consisent Hash

    问题描述 有一些目标节点 v1, v2...vn 需要一个算法,能够将任意key映射到目标节点中的一个vx 评价方式 1. 对于一个比较大的key集合,分布在各个目标节点的key的数量要尽可能均匀 2 ...

  9. Unity加载本地图片的2种方式

    1. 使用 WWW 加载,详细查看 unity3d 官方文档. 2. 使用 System.IO 加载,lua 代码如下: local File = luanet.import_type("S ...

  10. 我的云服务之WWW

    云服务器系统是:[root@ip-172-31-27-132 system]# cat /etc/redhat-release Red Hat Enterprise Linux Server rele ...