字符串算法————hash哈希鏈表

雖然已經有映射函數map,而且其適用範圍還更廣,但在字符串上還是哈希更好理解~~(哈希在密碼學上很重要,抱有某種目的同學們注意危險言論了)~~
學過高中生物的同學們應該對胞間連絲印象很深,hash和map就是一種信息學胞間連絲,很形象。
hash是一種對應法則,將字符串按照這種法則運算,所得的權值有可能會有重複(下文稱爲衝突),所以我們運算字符串的權值時會採用其他進制,根據題意需具體分析。FOR INSTANCE,若只會出現小寫字母則31進制足以撐場,但如果是大小寫字母都有,那就要用131進制比較合適了。
模板如下:

const int base=131;
inline int hash(string c){
	int len=c.size();
	int ret=0;
	for(int i=0;i<=len-1;i++){
	 	ret*=base,ret+=c[i]-'A';
	}
	return ret;
}

這裏的base就是進制了,具體情況具體分析。

好了,那我們如何儲存字符串信息呢?
這裏要用鏈表了,也就是哈希表。
因爲我們計算完哈希值後,要表明這個字符串被加進了字典中,按樸素思想應該直接flag[hash(s)]=1,但這樣數組flag會開的很大,根本存不下,所以我們對哈希值採用取模(模數不要太大,我比較喜歡19997),優先選擇質數~~,比如19260817這時有同學就要疑惑了,這不明顯會出問題嗎? 比如1%19997=1,19998%19997==1,不就會衝突了嗎?

嘿嘿,這時鏈表就有用了。
我們開一個結構體,儲存兩個信息:val和nt;
nt很明顯是存下一個節點的,而val則用來儲存字符串的原hash值
當我們算出hash(s)==v時,設t=v%mod,就在t的後面拉一條鏈,串起來。

代碼:

struct node{
	int nt,val;
}e[200018];
inline void update(string s){
	int x=hash(s);
	cnt++;
	e[cnt].nt=head[x%mod];
	e[cnt].val=x;
	head[x%mod]=cnt;
}

當我們查找字典中是否存在字符串s時,先計算出其哈希值x,如果存在,那麼它一定會被保存在x%mod後面,我們只需在x%mod後面的那條鏈裏掃一遍,查看是否有一個點權值爲x就OK了。
代碼:

inline int ask(string ch){
	int flag=0;
	int x=hash(ch);
	for(int i=head[x%mod];i;i=e[i].nt){
		if(e[i].val==x){
			flag=1;
		}
	}
	return flag;
}

}
ps:head[k]數組存的是k號拉鍊後面的第一個點在e數組中的編號(但實際上這個點是最後一個插入此鏈的)

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