KMP算法研究

 变量定义:

      T :主串

     W:模式串

     next[i]:模式串中从第1个字符到第i+1个字符构成的子串的最大前缀后缀相等数目。

1.KMP算法简介

  KMP算法主要是功能便是判断模式串是否出现在主串中,并找出相应的出现位置。而在常规的暴力破解算法中,通常采用顺序比对的方法进行查找,也就是将模式串依次与主串的第1、2、3....个字符比较,直到找出与模式串相等的子串,这样就会造成信息的浪费。而在KMP算法中,对于每一个模式串我们会事先计算出模式串的内部匹配信息,在匹配失败时最大的移动模式串,以减少匹配次数。

2.KMP算法比较过程

假定主串T: a b a c a  a  b a c a b a 

   模式串M:a b a c a b

第一次比较:

Tabacaabacaba
Mabacab
第二次比较:
Tabacaabacaba
Mabacab
第三次比较:
Tabacaabacaba
Mabacab
 

  第一次比较中, 在T[5]与W[5]出现了不匹配,而T[0]~T[4]是匹配的,现在T[0]~T[4]就是上文中说的 已经匹配的模式串子串, 现在移动找出 最长的相同的前缀和后缀并使他们重叠.而对于移动的步数则由以下公式确定:
移动步数=上一步查找中相同的字符个数 -M中第一个不匹配字符的前一个字符的最大前缀后缀数
注解:
首先,前缀和后缀的解释如下
如: a b a b a b c
       后缀:通俗地说就是所有包含了尾部字符的字串,就是一个后缀,如c ,bc,abc,都是;
       前缀:当然是包含了第一个字符的子串了.
其次,就是在步数的移动上。在上一步的比较中,假设相等的子串为:a b a c a,则该子串的最大前缀后缀数为1,也就是前缀与后缀相等时,最大的长度为1.也就是说,在主串中从i到i+4,在模式串中从0到4,是分别对应相等的,在下次的移动中,为了尽可能多地增大移动步数,就将模式串中移动到主串该次前缀的位置,重新开始比较。
具体实现代码如下:(时间很晚了,注释就明天起来再加)
#include<iostream>
#include<string>

using namespace std;
void getNext(string W, int *next);
void KMPsearch(string T,string W,int *next);
int main(void){
	int n = 0;
	string T,W;
	cin >> T;
	cin >> W;
	n = W.length();
	int *next=new int[n];
	getNext(W,next);
	KMPsearch(T,W,next);
	delete []next;
	return 0;
}
void KMPsearch(string T, string W, int *next){
	int m = 0, n = 0, i = 0, j = 0;
	n = T.length();
	m = W.length();
	while (i < n){
		if (T[i] != W[j] && j != 0){
			i = i + j - next[j - 1];
			j = 0;
		}
		if (T[i] != W[j] && j == 0){
			i = i + 1;
		}
		if (T[i] == W[j]){
			i++;
			j++;
		}
		if (j == m){
			cout << "Location: " << i - m + 1<< endl;
			return;
		}
	}
}

void getNext(string W, int *next){
	int m = W.length();
	next[0] = 0;
	for (int i = 1; i < m; i++){
		if (W[i] == W[next[i - 1]]){
			next[i] = next[i - 1] + 1;
		}
		else{
			next[i] = 0;
		}
	}
	/*for (int i = 0; i < m; i++){
		cout << next[i] << endl;
	}*/
}

 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值