在字符串中尋找子字符串

       Sunday算法是Daniel M.Sunday於1990年提出的一種比BM算法搜索速度更快的算法。其核心思想是:在匹配過程中,模式串並不被要求一定要按從左向右進行比較還是從右向左進行比較,它在發現不匹配時,算法能跳過儘可能多的字符以進行下一步的匹配,從而提高了匹配效率。

假設在發生不匹配時S[i]≠T[j],1≤i≤N,1≤j≤M。此時已經匹配的部分爲u,並假設字符串u的長度爲L。如圖1。明顯的,S[L+i+1]肯定要參加下一輪的匹配,並且T[M]至少要移動到這個位置(即模式串T至少向右移動一個字符的位置)。
圖1 Sunday算法不匹配的情況
分如下兩種情況:
(1) S[L+i+1]在模式串T中沒有出現。這個時候模式串T[0]移動到S[L+i+1]之後的字符的位置。如圖2。
圖2 Sunday算法移動的第1種情況
(2)S[L+i+1]在模式串中出現。這裏S[L+i+1]從模式串T的右側,即按T[M-1]、T[M-2]、…T[0]的次序查找。如果發現S[L+i+1]和T中的某個字符相同,則記下這個位置,記爲k,1≤k≤M,且T[k]=S[L+i+1]。此時,應該把模式串T向右移動M-k個字符的位置,即移動到T[k]和S[L+i+1]對齊的位置。如圖3。
圖3 Sunday算法移動的第2種情況
依次類推,如果完全匹配了,則匹配成功;否則,再進行下一輪的移動,直到主串S的最右端結束。該算法最壞情況下的時間複雜度爲O(N*M)。對於短模式串的匹配問題,該算法執行速度較快。
Sunday算法思想跟BM算法很相似,在匹配失敗時關注的是文本串中參加匹配的最末位字符的下一位字符。如果該字符沒有在匹配串中出現則直接跳過,即移動步長= 匹配串長度+1;否則,同BM算法一樣其移動步長=匹配串中最右端的該字符到末尾的距離+1。
現舉個例子來說明:
比如:
匹配串:O U R S T R O N G X S E A R C H
模式串:S E A R C H
這裏我們看到O-S不相同,我們就看匹配串中的O在模式串的位置,沒有出現在模式串中。
匹配串:O U R S T R O N G X S E A R C H
模式串: _ _ _ _ _ _ _ _S E A R C H
移動模式串,使模式串的首字符和O的下一個字符對齊。
匹配串:O U R S T R O N G X S E A R C H
模式串:_ _ _ _ _ _ _ _ S E A R C H
繼續比較,N-S不相同,字符R出現在模式串,則後移模式串,將把它們對齊
匹配串:O U R S T R O N G X S E A R C H
模式串: _ _ _ _ _ _ _ _ _ _ _ S E A R C H

#include <iostream>

using namespace std;

bool Appear(const char *s, const char &c)
{
	if(s==NULL)
		return false;
	while(*s!='\0')
	{
		if(*s==c)
			return true;
		s++;	
	}
	return false;
}

int Sunday(const char *src, const char *des)
{
	if(*src==NULL || *des==NULL)
		return 0;

	int len_s = strlen(src);
	int len_d = strlen(des);
	int pos[256];
//	cout<<sizeof(pos)<<endl;
//	memset(pos,6,1024);   //這樣是不行的,但是初始化爲0還是可以的

	int i=0;
	for(i=0;i<256;i++)
		pos[i] = len_d;

	for(i=0; i<len_d; i++)  //當src[k]與第一個字符不相等時,需要跳躍的步長
		pos[des[i]] = len_d - i;  //將src中的位置向後移動到字符串S,按照例子是從N移動到S

	for(i=0;i<256;i++)
		cout<<pos[i];
	cout<<endl;

	int index = 0;
	int k=0;
	bool flag = false;
	while(index < len_s)
	{
		k=index;
		for(i=0;i<len_d;i++)
		{
			if(src[k]!=des[i])
			{
				index = index + pos[src[k]];    
				break;
			}
			else
				k++;
		}
		if(i==len_d)
			return index;

		if(Appear(des, src[index]))    //如果尾字符在des中出現,則移動src
			index = k + pos[src[index]];    //這兒不能是index,而是k,因爲index會在上面不等的時候多加了一個pos[src[k]];
		else
			index = index + 1;        //如果尾字符不在des中出現,則移動一個值到N
	}
	return -1;
}

int main()
{
	char a[]={"ourstrongxsarchsearchi"};
	char b[]={"search"};
	cout<<Sunday(a,b)<<endl;
	return 0;
}


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