鉴于原理有点复杂,详细原理可以参考这篇文章http://blog.csdn.net/v_july_v/article/details/7041827

  本文直接从结论入手,应付考试和竞赛足够了。

  设T为目标串("aaabbbaabbabcabcabbaba"),pat为模式串("aabbabc")。

  这是模式串的next数组:

j(下标) 0 1 2 3 4 5 6
pat a a b b a b c
next[j] -1 0 1 0 0 1 0

  KMP算法:

  j=0时,next[j]=-1。表示下一趟匹配比较时,模式串的第-1个字符与目标串上次失配的位置对齐。(其实等同于第0个字符与目标串上次失配的下一个位置对齐),模式串需要移动到posT-next[j]的位置。(posT为T串下标)

  j=1时,next[j]=0。表示下一趟匹配比较时,模式串的第0个字符与目标串上次失配的位置对齐。模式串需要移动到posT-next[j]个位置。

  j=2时,next[j]=1。表示下一趟匹配比较时,模式串的第1个字符与目标串上次失配的位置对齐。模式串需要移动到posT-next[j]个位置。

  以此类推......

  

  那么下面只要求出next数组即可,next数组是如何形成的?

  从下标0开始,一直到lengthP-1为止(lengthP是模式串的长度),每次寻找该下标前面前缀与后缀相同的最大长度(前后缀不包括前面整个字符串,即起始位置和终止位置都相等的那一个字符串,下面有解释)。

  j=0时,字符a前面无字符,故标记-1;

  j=1时,字符a前面有字符a,但由于“前后缀不包括前面整个字符串”的规则,所以并没有相同的前后缀一说,故标记为0。

  j=2时,字符b前面有字符aa,前后缀相同的字符串为a,故标记为前后缀的长度1。

  以此类推......(PS:前后缀的计算都是从左到右的)

  其实这样说是为了方便理解next数组,而next数组的实际形成也是一次KMP算法,它也是一个匹配字符串的过程,用后缀去匹配前缀的过程。

  代码如下:

  

 #include<iostream>
#include<string>
using namespace std;
string T;
string pat;
void getNext(int next[],int lengthP){//lengthP为模式串P的长度
int j=,k=-;//j为P串的下标,k用来记录该下标对应的next数组的值
next[]=-;//初始化0下标下的next数组值为-1
while(j<lengthP){ //对模式串进行扫描
if(k==-||pat[j]==pat[k]){//串后缀与前缀没有相等的子串或者此时j下标下的字符与k下的字符相等。
j++;k++;
next[j]=k;//设置next数组j下标的值为k
}else
k=next[k];//缩小子串的范围继续比较
}
} int kmp(int k,int next[]){
int posP=,posT=k;//posP和posT分别是模式串pat和目标串T的下标,先初始化它们的起始位置
int lengthP=pat.length();//lengthP是模式串pat长
int lengthT=T.length();//lengthT是目标串T长
while(posP<lengthP&&posT<lengthT){//对两串扫描
if(posP==-||pat[posP]==T[posT]){//对应字符匹配
posP++;posT++;
}else
posP=next[posP];//失配时,用next数组值选择下一次匹配的位置
}
if(posP<lengthP) return -;
else return posT-lengthP;//匹配成功
} int main(){
T="aaabbbaabbabcabcabbaba";
pat="aabbabc";
int lengthP=pat.length();
int next[lengthP]={};
getNext(next,lengthP);
int pos=kmp(,next);
cout<<pos<<endl;
cout<<"next[]:";
for(int i=;i<lengthP;i++){
cout<<next[i]<<" ";
}
return ;
}

  

  

  

  

  

最新文章

  1. Android Studio常用快捷键
  2. 【PHP面向对象(OOP)编程入门教程】11.类的继承
  3. JS常用语句
  4. [ASP.Net]TableLayoutPanel的使用
  5. SERVER 2012 R2 core域环境下批量创建用户
  6. VB 增强的部件与引用
  7. 构建高可用web站点学习--前言
  8. [QT Creator]LNK1123: 转换到 COFF 期间失败: 文件无效或损坏 。
  9. PAT (Advanced Level) 1093. Count PAT&#39;s (25)
  10. 深入理解PHP对象注入
  11. I2S协议
  12. Fastjson反序列化漏洞研究
  13. ibatisNet MERGE INTO ORA-00911: 无效字符
  14. 背水一战 Windows 10 (104) - 通知(Toast): 纯文本 toast, 短时 toast, 长时 toast, 图文 toast
  15. Android-IntentFilter
  16. 【Linux】处理数据文件
  17. ubuntu普通账户获取root权限的方法以及su和su -的区别
  18. masonry瀑布流的使用
  19. Linq 常用方法解释
  20. axios常用操作

热门文章

  1. kerberos环境下spark消费kafka写入到Hbase
  2. SQLserver2008一对多,多行数据显示在一行
  3. Linux新增和删除环境变量
  4. shell 编程初级
  5. QMainWindow class
  6. flask wtforms组件详解
  7. day07(数据类型的相互转换 ,字符编码)
  8. Photoshop快速给美女人像换头发
  9. C#关于TreeView树在节点数较多时总是会出现闪烁的问题方法记录
  10. tomcat 进程莫名停止