字符串匹配中的KMP算法

以前在给定的字符串 s[ ] 中查找给定的子串 p[ ] 都是采用一般思路方法,即将 p 串中的每一位依次与 s 串中的每一位想比较,相同时则继续下一位的比较,不同时p又从头开始,s 上一次开始比较的地方开始,在依此进行比较,直到比较到它们其中一个的结尾。

int BFmatch(char *s,char *p)
{
	int i = 0, j = 0;
	int slen = strlen(s);
	int plen = strlen(p);
	while(i < slen && j < plen) {
		if(s[i]  == p[j]) {
			i++;
			j++;
		}
		else {
			i = i-j+1;
			j = 0;
		}
	}
	if(j == strlen(p))
		return i-j;
	else
		return -1;
}

这种方法是可行的也比较容易想到,但是效率不高。于是好心的人们发明了 KMP 算法,使得每次失配之后,不必总是回到 p[ ] 的开头重新比较,这样就提高了匹配查找的速度。

方法是将 p[i] 元素 之前 的前缀和后缀相同的最大长度值存入 next[i] 中,当 p[i] 与 s[ ] 中某个元素失配时,就将从p[next[i]] 开始比较。

int KMPmatch(char s[], char p[], int next[])
{
	int i =0, j = 0;
	int slen = strlen(s);
	int plen = strlen(p);
	while(i < slen && j < plen) {
		if(j == -1 || s[i] == p[j]) {   //  j=-1表示前一次匹配中第一个字符就不相同  
			i++;
			j++;
		}
		else
			j = next[j];
	}
	if(j == plen)
		return i - j;
	else
		return -1;
}

如何求得 next[ ]就是一个关键的问题了。

/*  如何求 next[], 采用递推的方法,假设我们已经知道了 next[j],那么如何求 next[j+1]
 *  首先 next[0] = -1, 已知 p[] 中 0 -> (k-1) 与 (j-k) -> (j-1) 是匹配的,若 p[j] == p[k]
 *  则 next[j+1] = next[j]+1 = k+1; 否则采取递推方式,令 k = next[k] (具体什么原因请看下面的图)
 *  这样推下去,会存在两种情况:1、p[k] 一直 != p[j],这样 最后k = next[k=0] = -1; 
 *  从而进入 if 条件得出next[j]=0;2、或者某个时候有 p[k] == p[j] 则 也将进入 if 循环得出next[j]
 *  (注意 j 是增加的)
 *            0  1  2  3  4  5  6  7
 *    p[]     a  b  b  c  a  b  b  d
 *   next[]   -1 0  0  0  0  1  2  3
 */
void getnext(char p[], int next[])
{
	int k = -1;
	int j = 0;
	int plen = strlen(p);
	next[0] = -1;
	while(j < plen-1) {
		if(k == -1 || p[k] == p[j]) {       
			k++;
			j++;
			next[j] = k;
		}
		else
			k = next[k];
	}
}

《字符串匹配中的KMP算法》

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/imlei2008/article/details/39779613
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞