KMP

推荐博客 :http://www.cnblogs.com/yjiyjige/p/3263858.html

什么是KMP 算法呢 ?

  KMP是三位大牛:D.E.Knuth、J.H.Morris和V.R.Pratt同时发现的。

问题 :

  有两个字符串 , 一个叫模式串 , 一个叫主串 , 用模式串向主串匹配 , 传统的方法 , 暴力匹配,当模式串与主串不匹配时 ,模式串与主串都回溯, 用模式串向主串的下一个字母匹配 。

这种暴力匹配效率很低 , 于是就产生了KMP这种思想 :  利用已经部分匹配这个信息,保持主串指针不回溯,通过修改模式串指针,让模式串尽量的移动到有效的位置。

还有这个 :

我感觉 , kmp 就是把人脑一眼可以看到的字符串匹配写成了机器语言 , 好了 , 下面介绍下如何确定 当模式串与主串不匹配时,如何求出模式串应该右移的位数 , 就会引入一个叫 next 的数组 。

next 数组所存的东西就是当两个串不匹配时 , 模式串指针应该跳跃的位置 ,看一个图

如何求next 数组呢 ?

  代码示例 :

  

void getnext(){
    int i = 0, j = -1; // i表示后缀指针,j表示前缀指针
    next[0] = -1;
    while (i != lenp){ // lenp 表示模式串长度
        if(j == -1 || s[i] == s[j]) { // s 所存的是模式串
            i++;
            j++;
            next[i] = j;
        }
        else 
            j = next[j];
    } 
}

// 前缀时确定的,后缀是相对的

关于next 有两种写法 , 一种是第一个元素内的值为 -1 , 一种是为 0, -1的版本在跳跃移动的时候更好理解一些 。

两个穿匹配的代码示例:

void kmp(){
    int i = 0, j = 0;
    while (i != lens && j != lenp){ 
        if (s[i] == p[j] || j == -1) { // p 所存的是主串
            i++;
            j++;
        }
        else j = next[j]; // 两个串相匹配,当不匹配时,模式串回跳 
                          // 当第一个字母都不匹配时,j 的值会被赋值为 -1
                          // 当 j 的值等于 模式串长度时,即证明已此时两个串已全部匹配
    }
}

 举个小例子 :

  比如abababab 与 abab 匹配 , 他们上来就可以实现全部匹配 , 接下来 模式串的指针就可以移动到 j = 2 的位置  即 a , 会继续与主串相匹配 。

上面的程序其实是 MP 的代码,它会有一个弊端,如 abcabcd,当第 6 个字母 c 不匹配时会跳到第 3 个字母 c ,其实这样是没有必要的

MP中,P[Next[i]]可能会与P[i]相等,那么其实 还是无法与目标串匹配,在KMP中创建Next数组时,加入了,P[i]不同于P[Next[i]]的条件

MP -> next

void GetNext(char p[],int m){
	int i=0,j=-1;
	Next[0]=-1;
	while(i<m){
		if(j==-1||p[i]==p[j]){
			i++;
			j++;
			Next[i]=j;
		}
		else{
			j=Next[j];
		}
	}
	//Next[m]=0  作用同上
}

KMP -> next

void GetNext(char p[],int m){
	int i=0,j=-1;
	Next[0]=-1;
	while(i<m){
		if(j==-1||p[i]==p[j]){
			i++;
			j++;
			if(p[i]==p[j]){
				Next[i]=Next[j];
			}
			else{
			    Next[i]=j;
			}
		}
		else{
			j=Next[j];
		}
	}
	//Next[m]=0  作用同上
}

  

东北日出西边雨 道是无情却有情
原文地址:https://www.cnblogs.com/ccut-ry/p/7625311.html