不知道看了几遍的kmp,反正到现在都没有弄清楚next[j]的计算和kmp的代码实现,温故而知新,经常回来看看,相信慢慢的就回了

从头到尾彻底理解KMP

理解KMP

/*!
* \file KMP_算法.cpp
*
* \author ranjiewen
* \date 2017/02/12 16:12
*
*/ void preKmp(const char* pattern, int m, int kmpNext[]) //和GetNextval等价
{
int i, j;
i = ;
j = kmpNext[] = -;
while (i<m)
{
while (j>- && pattern[i] != pattern[j]) // i为后缀,j为前缀
{
j = kmpNext[j];
}
i++;
j++;
if (pattern[i] == pattern[j])
{
kmpNext[i] = kmpNext[j];
}
else
{
kmpNext[i] = j;
}
}
} #include <iostream>
using namespace std;
#include <string> void KMP(string p, string t)
{
int m = p.length();
int n = t.length();
if (m>n)
{
cerr << "Unsuccessful match!";
}
const char* x = p.c_str();
const char* y = t.c_str(); int i = , j = , kmpNext[];
preKmp(x, m, kmpNext); i = j = ;
while (i<n)
{
while (j>- && x[j] != y[i])
{
j = kmpNext[j];
}
j++;
i++;
if (j >= m)
{
cout << "Matching index found at:" << i - j << endl;
j = kmpNext[j];
}
}
}
int main(int argc, char** argv) { string p1 = "abcabcad";
string p2 = "adcadcad";
string p3 = "ababcaabc";
string t = "ctcabcabcadtcaabcabcadat"; cout << "KMP: " << endl;
KMP(p1, t); // cout<<"KMP: "<<endl;
// KMP(p2, t); // cout<<"KMP: ";
// KMP(p3, t); return ;
}
  • 以后kmp算法都按照这样写
void GetNext(char* p, int next[])
{
int pLen = strlen(p);
next[] = -;
int k = -;
int j = ;
while (j < pLen - ) //j<pLen也没有错
{
//p[k]表示前缀,p[j]表示后缀
if (k == - || p[j] == p[k])
{
++k;
++j;
next[j] = k; //对于值k,已有p0 p1, ..., pk-1 = pj-k pj-k+1, ..., pj-1,相当于next[j] = k。
}
else //当不匹配时,更新新的前缀下标
{
k = next[k];
}
}
} // 优化的地方
//当p[j] != s[i] 时,下次匹配必然是p[next[j]] 跟s[i]匹配,如果p[j] = p[next[j]],必然导致后一步匹配失败(因为p[j]已经跟s[i]失配,
//然后你还用跟p[j]等同的值p[next[j]]去跟s[i]匹配,很显然,必然失配),所以不能允许p[j] = p[next[j]]。
//优化过后的next 数组求法
void GetNextval(char* p, int next[])
{
int pLen = strlen(p);
next[] = -;
int k = -; //前缀
int j = ;
while (j < pLen - ) //j<pLen也没有错
{
//p[k]表示前缀,p[j]表示后缀
if (k == - || p[j] == p[k])
{
++j;
++k;
//较之前next数组求法,改动在下面4行
if (p[j] != p[k])
next[j] = k; //之前只有这一行
else
//因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]]
next[j] = next[k];
}
else
{
k = next[k];
}
}
} int KmpSearch(char* s, char* p)
{
int i = ;
int j = ;
int sLen = strlen(s);
int pLen = strlen(p); int next[] = { };
GetNextval(p,next); while (i < sLen && j < pLen)
{
//①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
if (j == - || s[i] == p[j])
{
i++;
j++;
}
else
{
//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
//next[j]即为j所对应的next值
j = next[j];
}
}
if (j == pLen)
return i - j; //此处i-j才是字符串开始匹配的地方
else
return -;
}

有这样写的,else效果就是j==-1的时候

 while (Text[i] != '\0' && Pattern[j] != '\0')
{
if (Text[i] == Pattern[j])
{
++i;// 继续比较后继字符
++j;
}
else
{
index += j - next[j];
if (next[j] != -)
j = next[j];// 模式串向右移动
else
{
j = ;
++i;
}
}
}//while

算法之美--3.2.3 KMP算法的更多相关文章

  1. 字符串查找算法总结(暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法)

    字符串匹配是字符串的一种基本操作:给定一个长度为 M 的文本和一个长度为 N 的模式串,在文本中找到一个和该模式相符的子字符串,并返回该字字符串在文本中的位置. KMP 算法,全称是 Knuth-Mo ...

  2. JavaScript 数据结构与算法之美 - 十大经典排序算法汇总(图文并茂)

    1. 前言 算法为王. 想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手:只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 ...

  3. 算法之美--3.2.2 MP算法

    这块硬骨头,放在这里半年的时间了,一直没有动,今天周末看看,书上把过程写的比较详细,自己基本也看懂了,但是对代码本身的编写还是比较生疏,要经常复习,估计才能看透,后面有看了kmp;这两者之间的关系也是 ...

  4. 利用KMP算法解决串的模式匹配问题(c++) -- 数据结构

    题目: 7-1 串的模式匹配 (30 分) 给定一个主串S(长度<=10^6)和一个模式T(长度<=10^5),要求在主串S中找出与模式T相匹配的子串,返回相匹配的子串中的第一个字符在主串 ...

  5. KMP算法(转载)

    转载http://blog.csdn.net/yutianzuijin/article/details/11954939 kmp算法又称“看毛片”算法,是一个效率非常高的字符串匹配算法.不过由于其难以 ...

  6. kmp算法简明教程

    在字符串s中寻找模式串p的位置,这是一个字符串匹配问题. 举例说明: i = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 s = a b a a c a b a a a b a a ...

  7. 字符串模式匹配KMP算法

    一篇不错的博客:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html KMP字符串模式匹配通俗点说就是一种在一个字符串中 ...

  8. kmp算法理解与记录

    字符串匹配的暴力解法 给定字符串s和p,寻找字符串p在字符串s中出现的位置,暴力解法如下所示: 如果当前字符匹配成功,++i;++j,继续匹配下一字符. 如果s[i]与s[j]匹配失败,令i-=(j- ...

  9. 串匹配模式中的BF算法和KMP算法

    考研的专业课以及找工作的笔试题,对于串匹配模式都会有一定的考察,写这篇博客的目的在于进行知识的回顾与复习,方便遇见类似的题目不会纠结太多. 传统的BF算法 传统算法讲的是串与串依次一对一的比较,举例设 ...

随机推荐

  1. 使用代码生成器“代码工厂”快速生成B/S程序代码

    开发目的: 自动生成C#.HTML.JS.Ajax 代码 .可以节省大量的时间来做业务逻辑的代码,那些重复的代码就不需要....了 环境支持: 硬件环境:window .VS2010+.支持SQLSe ...

  2. [转]mysql Access denied for user 'root'@'localhost' 问题的解决方法

    解决方案如下: # /etc/init.d/mysql stop # mysqld_safe --user=mysql --skip-grant-tables --skip-networking &a ...

  3. Selenium WebDriver-通过ActionChains实现页面元素拖拽

    #encoding=utf-8 import unittest import time import chardet from selenium import webdriver class Visi ...

  4. Zookeeper在windows环境下安装

    1.已安装JDK并配置好了环境变量 2.下载Zookeeper,在清华大学镜像下载,选择合适版本  https://mirrors.tuna.tsinghua.edu.cn/apache/zookee ...

  5. NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config的问题

    故障问题: 使用springMVC3.05 ,tomcat服务器进行开发, Spring配置正确,console有输出,但是url打开时不能出现页面,提示错误信息为:NoClassDefFoundEr ...

  6. 面向对象编程(四)继承,概念及super关键字,final关键字,Object类常见方法

    继承 概念: ①   继承背后的思想就是基于已存在的类来构建新类; ②   当从已存在类继承时,就重用了它的方法和属性,还可以添加新的方法和属性来定制新类以应对需求; ③   当从其它类导出的类叫作子 ...

  7. 进程,线程,以及Python的多进程实例

    什么是进程,什么是线程? 进程与线程是包含关系,进程包含了线程. 进程是系统资源分配的最小单元,线程是系统任务执行的最小单元. 打个比方,打开word,word这个程序是一个进程,里面的拼写检查,字数 ...

  8. wine-qq 安装

    http://www.bubuko.com/infodetail-343048.html

  9. POJ——1611The Suspects(启发式并查集+邻接表)

    The Suspects Time Limit: 1000MS Memory Limit: 20000K Total Submissions: 31100 Accepted: 15110 Descri ...

  10. 浅谈android反调试之 签名校验

    反调试原理 很多时候,我们都需要进行修改修改应用程序的指令,然后重打包运行,重新打包就需要充签名. 利用签名的变化我们用于反调试.反调试实现代码如下: 为了更加隐藏,比较函数可能在SO层进行实现,如下 ...