数据结构(C语言实现)-串的模式匹配(KMP算法)

字符串是由多个字符组成的有限序列。记为s=‘a1 a2 a3 … an’,s为串的名,单引号引起来的是串的值。

在串中取出一段连续的字符构成一个新的序列,这个子序列称为串的子串。

找出子串在主串中的位置,称为模式匹配。将主串也即目标串记为S,用来匹配的子串也即模式串记为T,模式串在目标串中的位置记为pos。

举例:目标串S=‘searching for a string’,模式串T=‘for’,则T在S中的位置pos=11。

在传统的BF算法中,用两个指针指向S和T中正在进行比较的两个字符在各自串中的位置,这里我们用i指向目标串,用j指向模式串。然后在一个循环中依次比较主串和模式串中每一个字符,若不配,则进入下一循环,从主串中下一个字符开始比较…直到模式串匹配完成。
数据结构(C语言实现)-串的模式匹配(KMP算法)_第1张图片
这种算法最坏情况下的的时间复杂度为O(m*n),而在KMP算法中可以在O(m+n)的时间数量及上完成匹配。
KMP算法的一个特点是:i指针不进行回溯。
相应的要解决的问题是:主串中第i个字符与模式串中第j个字符失配时,下一步主串中第i个字符应与模式串中第几个字符进行比较?
解决方法是:引出模式串的next数组,当T第j个字符失配时,next数组对应位置上的值给出应该从T串的第几个元素与主串中的第i个元素进行比较。

核心:next数组如何建立。将模式串记为T=‘P1 P2 P3 … Pn’。假设T中第j个字符失配时,主串S中第i个字符应该与T中第k个字符开始比较。
则模式串应满足:‘P1 P2 … Pk-1’ = ‘P[j-(k-1)] P[j-(k-1)+1] … P[j-1]’ 示意图如下
数据结构(C语言实现)-串的模式匹配(KMP算法)_第2张图片
找到使红色部分相等的最长字符子串,即可得到next[j]=k,即下一轮从Pk开始比较。

以下是KMP算法的实现:

#include
#include
#include
#define OK 0
#define ERROR 1
#define MAXSTRLEN 64
typedef char SString[MAXSTRLEN+1];


// 生成值为chars,名为str的串,主要作用是生成第一位存储字符串长度的串
int StrAssign(SString str, char *chars)
{
	if (strlen(chars) > MAXSTRLEN)  return ERROR;
	else
	{
		str[0] = strlen(chars);  // 字符串第一位存储字符串长度
		for (inti = 1; i<= str[0]; i++)
			str[i] = *(chars + i - 1);  // 给str赋值
		return OK;
	}
}


// 生成next数组
void get_next(SString T, int next[])
{
	int j = 1;  // j指向模式串第j个字符,初始指向T1
	int k = 0;  // k指向模式串第next[j]个字符,初始指向T0
	next[1] = 0;  // 若第一个字符就失配,模式串直接向后移一位
	
	while (j <= T[0])
	{
		if (k ==0 || T[j] ==T[k])  // 第j个字符等于第k个字符时,next[j]=k
		{
			next[j] = k;
			k++;
			j++
		}
		else   // 第j个字符不等于第k个字符时,k回溯
			k = next[k];
	}
}


// KMP算法:返回T在S中的位置,若不存在则返回0
int Index_KMP(SString S, SString T, int &pos)
{
	pos = 1;
	int next[15];
	get_next(T, next);  // 获得next数组

	int j = 1;  // j指向模式串T中的元素
	while (pos <= S[0] && j <= T[0])
	{
		if(j ==0 || S[pos] == T[j])  // 模式串与目标串进行比较
			{pos++;  j++;}
		else j = next[j];  // 当T中第j个元素与S中第pos个元素不相等(不匹配时)
	}
	if(j > T[0])  // 模式串全部匹配完毕
		{pos = pos - T[0];   return OK;}
	else  // 匹配失败
		return ERROR;
}


int main()
{
	SString target = " ";  // 目标串初始化为空串
	SString mode = " ";  // 模式串初始化为空串
	int pos;
	
	char c[MAXSTRLEN + 1];
	printf("请输入目标串target:");
	gets_s(c);
	StrAssign(target, c);
	
	printf("请输入模式串mode:")gets_s(c);
	StrAssign(mode,c);

	Index_KMP(target,mode,pos);
	printf("position = %d \n",pos);

	system("pause");
	return 0;
}

你可能感兴趣的:(数据结构)