【数据结构】字符串-模式匹配

Brute Force

在这里插入图片描述

int StrBruteForce(LinkString* s, LinkString* t)
{
	LinkString* p = s;
	LinkString* p1;
	LinkString* q ;
	while (p->next)
	{
		q = t->next;
		p = p->next;
		p1 = p;
		while (p1 && q && p1->data == q->data)
		{
			p1 = p1->next;
			q = q->next;
		}
		if (!q )
			return true;
		if (!p1)
			return false;
	}
	return false;
}

KMP

  • KMP算法: 每次失配,S串的索引i不动,P串的索引j定位到某个数。T(n)=O(n+m),时间效率明显提高
    在这里插入图片描述

  • 这里关键是求一个模式串的Next数组

  1. 我们先把模式串标出序号:
    在这里插入图片描述
  2. 接着把模式串所有前缀依次列出来
    在这里插入图片描述
  3. 接下来把每一个子串相等的前缀和后缀的最大长度求出,举个例子”abaab“
  4. 观察子串,前后缀ab相同,因此返回2
    在这里插入图片描述
    5.依次类推,我们可以得到每一个子串对应的一组序列
    在这里插入图片描述
    当时这组数据并不是所要求的next数组,可以将其称为部分匹配值表,相应c代码如下
//获得部分匹配值表
void GetIndexStr(SqString* s,int next [])
{
	int i = 1;
	int j = 0;
	next[0] = 0;
	while (i	 < s->length)
	{
		if (s->data[i] == s->data[j])
			next[i++] = (j++) + 1;
		else if ( j ==0 && s->data[i] != s->data[j])
			next[i++] = 0;			
		else 
		j = next[j - 1];
	}
}
  1. 接着我们可以得到 首字为 -1 版本的next数组
  • 将上述得到的序列向右平移1位(去掉最后一个数),开头补上 -1 即可
    在这里插入图片描述
    相应c代码如下
//获得next数组 :相当于部分匹配值表右移1位,前插 - 1
void GetNextArr(SqString* s, int next[])
{
	int i =  0 ;
	int j =  -1 ;
	next[0] = -1;
	while (i < s->length - 1)
	{
		if (j == -1 || s->data[i] == s->data[j])
			next[++i] =++ j ;
		else j = next[j];
	}
}
  1. 要想得到严蔚敏版本的,即将上述序列全部元素+1即可,代码如下:
void GetNextArrAdd1(SqString* s, int next[])
{
	int i = 0;
	int j = -1;
	next[0] = j+1;
	while (i < s->length - 1)
	{
		if (j == -1 || s->data[i] == s->data[j])
			next[++i] = ++j +1;
		else
			j = next[j] - 1;
	}
}
  • 获取到next数组之后,接下来便是KMP算法的主流程
int KMPStr(SqString* s, SqString* t)
{
	int next[MAX_SIZE];
	int i = 0;
	int j = 0;
	GetNextArr(t,next);
	while (i < s->length && j<t->length)
	{
		if (j == -1 || s->data[i] == t->data[j])
		{
			i++;
			j++;
		}
		else j = next[j];
	}
	if (j >= t->length)
		return (i - t->length);
	else
		return -1;
}

改进KMP

  • 按前面的定义可以得到,next[j] = k
  • 若Tj=Tk,那么当Tj和Si不匹配时,也没必要将Si和Tk进行匹配
  • 因此直接将Si和T(next(k))进行匹配
void GetNextValArr(SqString* s, int nextVal[])
{
	int i = 0;
	int j = -1;
	nextVal[0] = -1;
	while (i < s->length - 1)
	{
		if (j == -1 || s->data[i] == s->data[j])
		{
			i++;
			j++;
			if (s->data[i] != s->data[j])
				nextVal[i] = j;
			else  nextVal[i] = nextVal[j];
		}
		else
			j = nextVal[j];
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章