【數據結構】字符串-模式匹配

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];
	}
}

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