KMP模式匹配算法

Posted on 2018-08-16 22:03  Apelike  阅读(159)  评论(0编辑  收藏  举报

KMP算法的难点在于next数组的求解。不同的书籍的KMP算法的next数组求解不一样,先看下不同版本的next数组求解结果:

对于模式串P=ababaca

《算法导论》:

 

《大话数据结构》:

 

 个人觉得《算法导论》的KMP算法更容易理解些,当然《大话数据结构》的KMP算法也会进行理解分享。

《算法导论》KMP模式匹配算法:

名词与记法:

PK:模式串ababaca有P0="",P1=a,P2=ab,P3=aba,P4=abab,P5=ababa,P6=ababac,P7=ababaca

前缀与后缀:字符串由X和Y拼接而成,记W=XY,X和Y至少含有一个字符,X叫做W的前缀,Y叫做W的后缀。例如,abcd的最长前缀为abc,最短前缀为a,abcd的最大后缀为bcd,最短后缀为d。

next求解公式:

 

C++代码实现:

void AlgorithmGetNextArray(string &P, vector<int>&next)
{
	int q, k;//q为模板字符串下标,k为最大前后缀长度,m为模板字符串长度
	next[0] = 0;//模板字符串的第一个字符的最大前缀长度为0
	for (q = 1, k = 0; q < P.size(); ++q)//从第二个字符开始计算,从头至此字符构成的字符串的最大相同前后缀的长度,即next值
	{
		while (k > 0 && P[q] != P[k])//当前字符串为Pq,最后一个字符为P[q]
			k = next[k - 1];//根据已经求得的next数组回溯,寻找Pq的前后缀交集中最大长度的字符串
		if (P[q] == P[k])//如果前缀的最后一个字符和P[q]相同,最大相同前后缀长度加1
		{
			k++;
		}
		next[q] = k;//Pq最大相同前后缀的长度为k
	}
}

  

int AlgorithmKMP(string &str, string&P, vector<int>&next)
{
	int i, q;
	AlgorithmGetNextArray(P,next);
	for (i = 0, q = 0; i < str.length(); ++i)
	{
		while (q>0&&P[q]!=str[i])
			q = next[q]-1;
		if (P[q] == str[i])
			q++;
		if (q == next.size())//next数组走完了
			return i - next.size() + 1;
	}
	return -1;
}

  

 《大话数据结构》KMP匹配算法:

next求解公式:

两种写法,第一种《算法导论》写法:

void DaHuaGetNextArray(string&P,vector<int>&next)
{
	int q,k;
	next[0] = 0;
	for (q = 1, k = 0; q < next.size(); ++q)
	{
		while (k>1&&P[q-1]!=P[k-1])
		{
			k = next[k-1];
		}
		if (k == 0 || P[q - 1] == P[k - 1])
		{
			k++;
		}
		next[q] = k;
	}
}

  

int DaHuaKMP(string &str, string&P, vector<int>&next)
{
	DaHuaGetNextArray(P,next);
	int i, q;
	for (i = 0, q = 0; i < str.length(); ++i)
	{
		if (str[i] == P[q])
		{
			++q;
		}
		else
			q = next[q];
		if (q == next.size())//next数组走完了
			return i - next.size()+1;
	}
	return -1;
}

  

 第二种,《大话数据结构》写法:

 草,就是不想加哨兵,暂时不会写不加哨兵的。。。。。。。。。。。。。。。