一.BF算法 --传统算法

BF算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串P的第一个字符进行匹配,若相等,则继续比较S的第二个字符和P的第二个字符;若不相等,则比较S的第二个字符和P的第一个字符,依次比较下去,直到得出最后的匹配结果。

举例说明:

S:  ababcababa

P:  ababa

  BF算法匹配的步骤如下

i=0                                   i=1                             i=2                         i=3                          i=4

第一趟:ababcababa         第二趟:ababcababa      第三趟:ababcababa    第四趟:ababcababa    第五趟:ababcababa

ababa                            ababa                          ababa                        ababa                       ababa

j=0                                   j=1                            j=2                         j=3                         j=4(i和j回溯)

void getNext(char *p,int *next)
{
int j,k;
next[]=-;
j=;
k=-;
while(j<strlen(p)-)
{
if(k==-||p[j]==p[k]) //匹配的情况下,p[j]==p[k]//k ==-1,代表着next[0]即模式串回到了开始位置
{
j++;
k++;
next[j]=k;
}
else //p[j]!=p[k]
k=next[k];
}
}

2.直接求解方法

i=1                                 i=2                           i=3                            i=4                        i=3

第六趟:ababcababa         第七趟:ababcababa       第八趟:ababcababa     第九趟:ababcababa   第十趟:ababcababa

ababa                              ababa                           ababa                        ababa                        ababa

j=0                                  j=0                           j=1                           j=2(i和j回溯)            j=0

i=4                                    i=5                          i=6                           i=7                          i=8

第十一趟:ababcababa       第十二趟:ababcababa    第十三趟:ababcababa   第十四趟:ababcababa   第十五趟:ababcababa

ababa                               ababa                           ababa                          ababa                          ababa

j=0                                    j=0                         j=1                            j=2                         j=3

i=9

第十六趟:ababcababa

ababa

j=4(匹配成功)

int BFMatch(char *s,char *p)
{
int i,j;
i=;
while(i<strlen(s))
{
j=;
while(s[i]==p[j]&&j<strlen(p))
{
i++;
j++;
}
if(j==strlen(p))
return i-strlen(p);
i=i-j+; //指针i回溯
}
return -;
}

其实在上面的匹配过程中,有很多比较是多余的。在第五趟匹配失败的时候,在第六趟,i可以保持不变,j值为2。因为在前面匹配的过程中,对于串S,已知s0s1s2s3=p0p1p2p3,又因为p0!=p1!,所以第六趟的匹配是多余的。又由于p0==p2,p1==p3,所以第七趟和第八趟的匹配也是多余的。在KMP算法中就省略了这些多余的匹配。

二.KMP算法

KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字。其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n)。

  在KMP算法中,为了确定在匹配不成功时,下次匹配时j的位置,引入了next[]数组,next[j]的值表示P[0...j-1]中最长后缀的长度等于相同字符序列的前缀。

  对于next[]数组的定义如下:

 1) next[j] = -1  j = 0

 2) next[j] = max(k): 0<k<j   P[0...k-1]=P[j-k,j-1]

 3) next[j] = 0  其他

如:

 P      a    b   a    b   a

 j      0    1   2    3   4

next    -1   0   0    1   2

 即next[j]=k>0时,表示P[0...k-1]=P[j-k,j-1]

因此KMP算法的思想就是:在匹配过程称,若发生不匹配的情况,如果next[j]>=0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配;若next[j]=-1,则将i右移1位,并将j置0,继续进行比较。

int KMPMatch(char *s,char *p)
{
int next[];
int i,j;
i=;
j=;
getNext(p,next);
while(i<strlen(s))
{
if(j==-||s[i]==p[j])
{
i++;
j++;
}
else
{
j=next[j]; //消除了指针i的回溯
}
if(j==strlen(p))
return i-strlen(p);
}
return -;
}

因此KMP算法的关键在于求算next[]数组的值,即求算模式串每个位置处的最长后缀与前缀相同的长度, 而求算next[]数组的值有两种思路,

第一种思路:

用递推的思想去求算,

还有一种就是直接去求解。

1.按照递推的思想:

根据定义next[0]=-1,假设next[j]=k, 即P[0...k-1]==P[j-k,j-1]

1)若P[j]==P[k],则有P[0..k]==P[j-k,j],很显然,next[j+1]=next[j]+1=k+1;

2)若P[j]!=P[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]。

因此可以这样去实现:

void getNext(char *p,int *next)
{
int j,k;
next[]=-;
j=;
k=-;
while(j<strlen(p)-)
{
if(k==-||p[j]==p[k]) //匹配的情况下,p[j]==p[k]
{
j++;
k++;
next[j]=k;
}
else //p[j]!=p[k]
k=next[k];
}
}

2.直接求解方法

void getNext(char *p,int *next)
{
int i,j,temp;
for(i=;i<strlen(p);i++)
{
if(i==)
{
next[i]=-; //next[0]=-1
}
else if(i==)
{
next[i]=; //next[1]=0
}
else
{
temp=i-;
for(j=temp;j>;j--)
{
if(equals(p,i,j))
{
next[i]=j; //找到最大的k值
break;
}
}
if(j==)
next[i]=;
}
}
} bool equals(char *p,int i,int j) //判断p[0...j-1]与p[i-j...i-1]是否相等
{
int k=;
int s=i-j;
for(;k<=j-&&s<=i-;k++,s++)
{
if(p[k]!=p[s])
return false;
}
return true;
}

【推荐使用第一种方法】

^_^^_^

C-KMP的更多相关文章

  1. KMP算法求解

    // KMP.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> using namespac ...

  2. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  3. KMP算法

    KMP算法是字符串模式匹配当中最经典的算法,原来大二学数据结构的有讲,但是当时只是记住了原理,但不知道代码实现,今天终于是完成了KMP的代码实现.原理KMP的原理其实很简单,给定一个字符串和一个模式串 ...

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

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

  5. [KMP]【学习笔记】

    Oulipo Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 36916   Accepted: 14904 Descript ...

  6. KMP算法实现

    链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...

  7. KMP专题

    1.[HDU 3336]Count the string(KMP+dp) 题意:求给定字符串含前缀的数量,如输入字符串abab,前缀是a.ab.aba.abab,在原字符串中出现的次数分别是2.2.1 ...

  8. KMP学习之旅

    说起kmp就要从字符串的匹配说起,下面我们谈谈字符串的匹配 给定一个原字符串:bababababababababb,再给定一个模式串:bababb,求模式串是否在源字符串中出现 最简单的方法就是遍历源 ...

  9. KMP模板

    参考:http://www.cnblogs.com/c-cloud/p/3224788.html #include<stdio.h> #include<string.h> vo ...

  10. 【字符串匹配】KMP算法和next数组的c/c++实现

    KMP算法基本思想有许多博客都写到了,写得也十分形象,不懂得可以参考下面的传送门,我就不解释基本思想了.本文主要给出KMP算法及next数组的计算方法(主要是很多网上的代码本人(相信应该是许多人吧)看 ...

随机推荐

  1. nyoj-709-异形卵(水题)

    异 形 卵 时间限制:1000 ms  |  内存限制:65535 KB 难度: 描写叙述 我们探索宇宙,是想了解浩瀚星空的奥妙.但我们却非常少意识到宇宙深处藏匿的危急,它们无时无刻不紧盯着我们的地球 ...

  2. Android API 中文(76)——AdapterView.OnItemLongClickListener

    前言 本章内容是android.widget.AdapterView.OnItemLongClickListener,版本为Android 2.3 r1,翻译来自"cnmahj", ...

  3. C++ 函数映射使用讲解

    想想我们在遇到多语句分支时是不是首先想到的是 switc case 和 if else if ... 这2种方式在编码方面确实简单少,但是当分支达到一定数量后,特别是分支内部有嵌套大段代码或者再嵌套分 ...

  4. cocos2d基础入门

    HelloCpp中Classes目录下放开发者自己的类: win32:平台相关,coco2d已默认创建:coco2d-x目录下,samples/cpp/HelloCpp/(工程根目录)图片放置位置:根 ...

  5. java之路径

    在学习java的过程中经常遇见关于路径的问题:到底是使用绝对路径还是相对路径? 个人推荐使用相对路径,如果是使用绝对路径,到后期项目发布的时候会出现许多问题. 那么相对路径怎么用来: 一. Syste ...

  6. [Swust OJ 412]--医院设置(floyd算法)

    题目链接:http://acm.swust.edu.cn/problem/412/ Time limit(ms): 1000 Memory limit(kb): 65535   Description ...

  7. HTML5 总结-表单-输入类型

    HTML5 Input 类型 HTML5 新的 Input 类型 HTML5 拥有多个新的表单输入类型.这些新特性提供了更好的输入控制和验证. 本章全面介绍这些新的输入类型: email url nu ...

  8. apache加载php模块失败

    LoadModule php5_module "G:/php54/php5apache2_2.dll" apache2 conf加入这个之后无法加载 解决办法 在这句之前加入PHP ...

  9. QLabel设置行间距(使用html的语法,比较巧妙)

    1.设置行间距 QLabel没有设置行间距的函数,所以这种办法是行不通的.只能采用其它类似的方法来实现,例如设置行高,使用样式代码如下: <p style='line-height:18px'& ...

  10. 从PyOpenCV到CV2

    安装cv2 http://hyry.dip.jp/files/opencv.zip 采用cv2重写的<Python科学计算>中的实例程序 读者可以在下面的页面中搜索“opencv”,并根据 ...