哈希表(HashTable)的構(gòu)造方法和沖突解決

關(guān)于哈希表里面的這些個(gè)定址和解決沖突的方法名詞我一直記不住,今天閑下來(lái)就花點(diǎn)時(shí)間來(lái)學(xué)習(xí)之、記錄之、分享之。

哈希函數(shù)構(gòu)造方法

構(gòu)造哈希函數(shù)的目標(biāo)是使得到的哈希地址盡可能均勻地分布在n個(gè)連續(xù)內(nèi)存單元地址上,同時(shí)使計(jì)算過(guò)程盡可能簡(jiǎn)單以達(dá)到盡可能高的時(shí)間效率。根據(jù)關(guān)鍵字的結(jié)構(gòu)和分布的不同,可構(gòu)造出許多不同的哈希函數(shù)。Java中的超級(jí)父類Object中就有得到哈希值的方法,以下是截取Java api 1.6中Object類說(shuō)明的一段

public int hashCode()返回該對(duì)象的哈希碼值。支持此方法是為了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。 hashCode 的常規(guī)協(xié)定是:

  1. 在 Java 應(yīng)用程序執(zhí)行期間,在對(duì)同一對(duì)象多次調(diào)用 hashCode 方法時(shí),必須一致地返回相同的整數(shù),前提是將對(duì)象進(jìn)行 equals 比較時(shí)所用的信息沒(méi)有被修改。從某一應(yīng)用程序的一次執(zhí)行到同一應(yīng)用程序的另一次執(zhí)行,該整數(shù)無(wú)需保持一致。
  2. 如果根據(jù) equals(Object) 方法,兩個(gè)對(duì)象是相等的,那么對(duì)這兩個(gè)對(duì)象中的每個(gè)對(duì)象調(diào)用 hashCode 方法都必須生成相同的整數(shù)結(jié)果。
  3. 如果根據(jù) equals(java.lang.Object) 方法,兩個(gè)對(duì)象不相等,那么對(duì)這兩個(gè)對(duì)象中的任一對(duì)象上調(diào)用 hashCode 方法不 要求一定生成不同的整數(shù)結(jié)果。但是,程序員應(yīng)該意識(shí)到,為不相等的對(duì)象生成不同整數(shù)結(jié)果可以提高哈希表的性能。
  4. 實(shí)際上,由 Object 類定義的 hashCode 方法確實(shí)會(huì)針對(duì)不同的對(duì)象返回不同的整數(shù)。(這一般是通過(guò)將該對(duì)象的內(nèi)部地址轉(zhuǎn)換成一個(gè)整數(shù)來(lái)實(shí)現(xiàn)的,但是 JavaTM 編程語(yǔ)言不需要這種實(shí)現(xiàn)技巧。)

下面具體說(shuō)說(shuō)構(gòu)造方法。可能在不同書(shū)籍上看到的方法名字不一樣,主要是理解思想。(定義關(guān)鍵字為k,哈希函數(shù)為h(k),表長(zhǎng)為m)

1.直接定址法

直接以關(guān)鍵字k或者k加上某個(gè)常數(shù)(k+c)作為哈希地址,即:h(k) = k + c這種哈希函數(shù)計(jì)算簡(jiǎn)單。當(dāng)關(guān)鍵字基本連續(xù)時(shí)用這種方法十分方便,若關(guān)鍵字不連續(xù)的話將造成內(nèi)存單元大量浪費(fèi)。

2.數(shù)字分析法

提取關(guān)鍵字中取值比較均勻的數(shù)字作為哈希地址。它適用于關(guān)鍵字都已知的情況,并需要對(duì)關(guān)鍵字中每一位的取值進(jìn)行分析。比如有80個(gè)記錄,關(guān)鍵字是一個(gè)8位的十進(jìn)制整數(shù):m1m2m3...m7m8,如哈希表長(zhǎng)度為100,則哈希表地址空間為0-99。進(jìn)過(guò)分析各關(guān)鍵字m1m2m3取值比較集中(多個(gè)關(guān)鍵字重復(fù)或相似)就不宜作為哈希地址;相反,門m4m5m7m8取值比較分散,則可根據(jù)需要選取若干位作為哈希地址,即:h(k) = m4m5m7 etc.

3.除留余數(shù)法

用關(guān)鍵字k除以某個(gè)不大于哈希表長(zhǎng)度m的數(shù)p,將所得余數(shù)作為哈希表地址。即:h(k) = k mod p;這種方法計(jì)算比較簡(jiǎn)單,適用范圍廣,是最經(jīng)常使用的一種哈希函數(shù)。這種方法的關(guān)鍵是選好p,使得元素集合中每一個(gè)關(guān)鍵字通過(guò)該函數(shù)轉(zhuǎn)換后映射到哈希表范圍的任意地址上的概率相等,從而盡可能減少?zèng)_突的可能性。

4.分段疊加法

按照哈希表地址位數(shù)將關(guān)鍵字分成位數(shù)相等的幾部分,其中最后一部分可以比較短。然后將這幾部分相加,舍棄最高進(jìn)位后的結(jié)果就是該關(guān)鍵字的哈希地址。分段疊加又可以分成折疊法和位移法兩種。位移法是將分割后的每部分低位對(duì)齊相加;折疊法是將奇數(shù)段正序偶數(shù)段逆序然后相加。

5.平方取中法

如果關(guān)鍵字各個(gè)部分分布都不均勻的話,可以先求出它的平方值,然后按照需求取中間的幾位作為哈希地址。因?yàn)槠椒街档闹虚g部分跟關(guān)鍵字的每一位都有相關(guān)性,所以產(chǎn)生隨機(jī)數(shù)的概率比較高。

6.偽隨機(jī)數(shù)法

插個(gè)嘴,最近看到這樣一句話:計(jì)算機(jī)中沒(méi)有正真的隨機(jī)數(shù),都是偽隨機(jī)數(shù),得到隨機(jī)數(shù)的方法都是程序員寫的代碼,當(dāng)然這里面的細(xì)節(jié)我就不是很清楚了。偽隨機(jī)數(shù)法是指采用一個(gè)偽隨機(jī)數(shù)當(dāng)作哈希函數(shù),即h(k) = random(k);

在判斷性能時(shí)通常要考慮4個(gè)因素:

  • 計(jì)算哈希函數(shù)所需要的時(shí)間。
  • 關(guān)鍵字的長(zhǎng)度
  • 關(guān)鍵字分布情況
  • 查找頻率

性能好的哈希函數(shù)能減少?zèng)_突,通常不可能完全避免沖突,所以解決沖突也是哈希表的另一個(gè)關(guān)鍵問(wèn)題。解決沖突在創(chuàng)建哈希表和查找時(shí)應(yīng)該保持一致。

處理哈希沖突

1.開(kāi)放定址法(再散列法)

在開(kāi)法定址法中,哈希表中的空閑單元(記為d)不僅允許哈希地址為d的同義詞關(guān)鍵字使用,而且也允許發(fā)生沖突的其他關(guān)鍵字使用。開(kāi)法定址法的名字就是來(lái)自于此方法的哈希表空閑單元既向同義詞開(kāi)放,也向發(fā)生沖突的非同義詞關(guān)鍵字開(kāi)放。誰(shuí)先找到這個(gè)單元誰(shuí)先占用,這和哈希表的元素排列次序有關(guān)。開(kāi)放定址法以發(fā)生沖突的地址d作為自變量來(lái)得到一個(gè)新的空閑單元,下面介紹常用的幾種。(d加下標(biāo)i記為d[i],小i打不出來(lái)==)

1.線性探查法

發(fā)生沖突時(shí),線性遍歷后續(xù)單元直到找到空閑單元。即d[i] = (d[i-1] + 1) mod m線性探查容易產(chǎn)生堆積的問(wèn)題。因?yàn)槿羰浅霈F(xiàn)了若干個(gè)同意詞會(huì)堆積在第一個(gè)同義詞的地址單元附近。

2.平方探查法

發(fā)生沖突時(shí),用平方探查法的探查序列為d[i] + 12,d[i] + 22, d[i] + 32...直到找到空閑單元。平方探查法是一種比較好的處理沖突的方法,可以避免堆積問(wèn)題。它的缺點(diǎn)是不能探查到哈希表上的所有單元,不過(guò)至少也能探查到一半單元。etc

2.鏈地址法(拉鏈法)

鏈地址法的思想是將哈希表的每個(gè)單元作為鏈表的頭結(jié)點(diǎn),所有哈希地址為i的元素構(gòu)成一個(gè)同義詞鏈表。即發(fā)生沖突時(shí)就把該關(guān)鍵字鏈在以該單元為頭結(jié)點(diǎn)的鏈表的尾部。(圖得靠自己腦補(bǔ))鏈地址法適用于經(jīng)常插入刪除的情況,其中查找、插入和刪除操作主要在同義詞鏈中進(jìn)行。

3.再哈希法

在構(gòu)造函數(shù)時(shí)同時(shí)構(gòu)造多個(gè)不同的哈希函數(shù)。當(dāng)哈希地址發(fā)生沖突用其他的函數(shù)計(jì)算另一個(gè)哈希函數(shù)地址,直到?jīng)_突不再產(chǎn)生為止。這種方法不易產(chǎn)生聚集,但增加了計(jì)算時(shí)間。

4.建立公共溢出區(qū)

建立公共溢出區(qū)的基本思想是將哈希表分為基本表和溢出表2部分,發(fā)生沖突的元素都放入溢出表中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,746評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,666評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,477評(píng)論 6 407
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,960評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,200評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,617評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,807評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,049評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,425評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,674評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,432評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,769評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容