一種字符串搜索方法

        在閱讀開源代碼過程中發現一種字符串搜索方法,仔細分析之後終於搞懂其原理了。雖然不知道這種搜索方法學術上叫什麼名字,但是對其構造跳轉表,跳躍搜索的方式很感興趣,所以記錄下來分享一下。

先看大致的代碼:

#define MAXCHAR 256
/*
 * key: 搜索關鍵字
 * shift_table: 跳轉表數組指針
 */
void ready(string key, unsigned int *shift_table){
	unsigned int k_length = key.length();
	int s;

	for(s = 0; s < MAXCHAR ; ++s){
		*(shift_table + s) = k_length;
	}
	//構造跳轉表
	for(s = 0; s < k_length; ++s){
		*(shift_table + key[s]) = k_length - 1 - s;
	}
}
/*
 * key: 搜索關鍵字
 * src: 搜索的源字符串
 * n:  搜索長度
 * 返回值: 關鍵字在源字符串中的開始位置
 */
int find(string key, string src, int n){
	unsigned int shift_table[MAXCHAR];
	ready(key, shift_table);
	int i,j,pos;
	int s = key.length() - 1;
    while(s < n){
		j = key.length() - 1;
		i = s;
		
		while( j >= 0 && (src[i] == key[j])){
			--j;
			--i;
		}
		if( j == -1){
			pos = i + 1;
			return pos;
		}
		++s;
		if (s > n){
			return -1;
		}

		s += shift_table[src[s]];
	}
}
其中最有意思的是

	//構造跳轉表
	for(s = 0; s < k_length; ++s){
		*(shift_table + key[s]) = k_length - 1 - s;
	}

	s += shift_table[src[s]];
這兩部分分別是構造跳轉表,和根據跳轉表跳轉到查詢匹配位置。

      跳轉表數組相當於字典,下標是每個ASCII碼的int值,下標對應的值是此字符在關鍵字中到最後一個字符的距離。比如key爲“Hello!”,則關鍵字字符對應的跳轉表爲

shift_table[72] = 5
shift_table[69] = 4
shift_table[76] = 2 //76字符是'l'。兩個'l',後面的會把前面的覆蓋
shift_table[79] = 1
shift_table[33] = 0
        在字符查找失敗時,根據跳轉表可以跳轉到合適的位置重新查找,避免了逐個字符循環查找的過程,提高了效率。
爲什說是"合適"的位置呢?

       比如說源字符串“SXEI0Hello!08uix”,關鍵字“Hello!”,先從源字符串“SXEI0H”處從後往前匹配,匹配不成功後,選擇下個位置繼續從後往前的匹配過程。最笨的匹配算法肯定是往後逐個增加字符重複匹配過程,但是很多是不必要的。“SXEI0H”匹配當然是不成功的,探測下個字符‘e’。'e'在關鍵字中也在存在,到最後一個字符距離是4,也就是說,如果此處的‘e’跟關鍵字中的‘e’能匹配上(包括位置),那麼後面的四個字符也應該能匹配的上,那麼就可以根據跳轉表直接跳到‘e’後的第四個字符開始從後往前匹配。如果‘e’後第四個字符匹配不上,那麼中間四個(包括‘e’字符)字符匹配上了也沒意義,這樣就直接跳過中間四個無意義的匹配過程。這就是爲什麼說跳轉表指明瞭每個字符"合適"的跳轉位置。



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