1. 程式人生 > >字串演算法————hash連結串列

字串演算法————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),這是有同學就要疑惑了,這不明顯會出問題嗎?比如1%199971,19998%199971,不就會衝突了嗎?

嘿嘿,這時連結串列就有用了。
我們開一個結構體,儲存兩個資訊: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陣列中的編號(但實際上這個點是最後一個插入此鏈的)