hlist 雜湊鍊錶介紹

2021-06-23 01:19:11 字數 3754 閱讀 9447

雜湊表又稱雜湊表,是為了加快元素查詢而設計的一種資料結構。基本原理是:把需要查詢的關鍵字通過對映函式(雜湊函式)對映到相應的儲存位址,然後直接訪問元素。需要儲存或者查詢的元素一般稱為關鍵字(key value),而這個對映函式一般稱為雜湊函式,對映到的儲存位址一般稱為雜湊表。

與陣列相比較:陣列通過陣列名和陣列下標可以很快的查詢、插入和修改。但刪除時,要把刪除元素後面的元素都往前移動乙個單元。

與列表相比較:列表則和陣列相反,刪除操作時非常容易。但插入,查詢和修改都要從列表頭開始遍歷、比較,然後才能做操作。

而雜湊表則既有兩種資料結構的優點,不管是查詢、插入、修改還是刪除,都可以由關鍵字通過雜湊函式直接找到要操作的元素,然後就可以直接操作了。當然了以上雜湊表的分析是基於沒有衝突碰撞,或者是衝突碰撞處理的比較好的情況。

雜湊函式:不確定長度的元素(資料,資訊等)通過雜湊函式壓縮成資訊摘要,形成固定格式的資訊。關鍵字key,則hash = f(key),則f(key)是雜湊函式,存放hash值的位址集為雜湊表。不同的關鍵字key,可以對映到同乙個雜湊值;但不可以是乙個關鍵字對映到多個雜湊值。即:函式可以一對一,也可以多對一,但不能一對多。當多對一(多個關鍵字雜湊到乙個位址上)時,稱為衝突碰撞現象。

乙個好的雜湊函式可以減少雜湊表中的衝突碰撞現象。下面介紹幾種雜湊函式的構造方法:

直接定址法:把雜湊函式構造成線性函式,這種方法可以徹底杜絕衝突碰撞現象。一般表達為:hash = kx + b;其實要杜絕雜湊表的衝突現象只要雜湊函式為單調性函式就可以了,或者更確切的說只要在關鍵字的區域內,雜湊函式是嚴格單調的函式,那麼就可以杜絕衝突現象了。其本質是單調函式x和y是一一對應的。

從這種方法思考延伸下去:因為乙個好的雜湊表其元素分布要盡量均勻。

例:關鍵字為: 3、12、21、33、54、78、93      雜湊函式為:hash = hash(x) = x   則生成的雜湊表將會有很多的空間浪費,而且分布很不均勻。若雜湊函式為:hash = hash(x) = 1/x   則生成的hash值分別為:1、4、7、11、18、26、31   這個雜湊表的區域明顯比前個雜湊表要分布更均勻些。所以用這種方法構造雜湊函式設計雜湊表時,可以考慮下函式的斜率。盡量讓雜湊表分布均勻。

第二種就是利用高數的微積分知識。  例:hash = hash(x) = x^2 - 6x + 8   若關鍵字的域為大於3,則是一對一的雜湊表。若關鍵字域在大於0的範圍內,那麼這是個多對一的雜湊表。即:會傳送雜湊表衝突碰撞現象。這個方法的本質是函式的單調性,可以把雜湊函式求導,求出hash極值時,關鍵字為3。所以若所有關鍵字域》3或者所有關鍵字《3都不會出現雜湊表衝突現象。這是個檢測雜湊表是否有衝突現象的很好的方法,也可以驗證雜湊函式設計的是否合理。

數字分析法:使用這種方法是在已知所有關鍵字的前提下,可以過濾掉易引起雜湊表衝突現象的關鍵字部分,只取關鍵字中的某個部分來運算後作為關鍵字的儲存位址。

例:關鍵字為乙個32位學生的班級全體學生的出生年月日資訊。這個可以用數字分析法來過濾掉易引起雜湊表衝突現象的某部分。分析:乙個班的同學,年齡都相仿,所以出生年號大部分是一樣的。若選用年號運算後來做儲存位址,則容易引起雜湊表衝突,故剔除掉年號。若用出生資訊中某日運算後作為儲存位址,則32個同學中一定會有同學產生的雜湊值相同,有雜湊表衝突。所以最後分析得:用月和日號一起作為關鍵字運算後當做儲存的位址。這樣出現雜湊衝突的現象就會大大減少。

平方取中法:

取關鍵字平方運算後的中間若干位為儲存位址,這個方法可以在不知道所有關鍵字的前提下使用。乙個數的平方後會擴大,取其中間的幾位數,一定和原來的數有關係。

例:關鍵字為:120、110、150、210、330、230

關鍵字的平方:14400、12100、22500、44100、108900、52900

捨去後面2位( (key*key) / 100 ),取3位數( ( (key*key) / 100 )%1000)作為儲存位址(也可以取4位,不足前面補0。這要看雜湊表的長度)

:144、121、225、441、089、529

摺疊法:將關鍵字分割成位數相同的幾部分,最後一部分的位數可以不同。然後取這幾部分的疊加和(捨去進製)作為雜湊位址。這個方法可以適用於關鍵字位數比較多的,並且關鍵字的位數不一致的情況。

例:關鍵字:12314、143211、17326、98271、83764

把關鍵字分割2部分,然後摺疊:

12314:12 + 31 + 4 = 47

143211:14 + 32 + 11 = 57

17326:17 + 32 + 6 = 54

83764:83 + 76 + 4 = 63 (同上捨去進製)

隨機法:隨機法是把關鍵字作為隨機因子然後通過隨機函式來生成的在一定範圍內的隨機數作為儲存位址。

例:srand((int)關鍵字);    //設定隨機因子

rand();              //生成隨機數

當然具體要生成的隨機數範圍可以根據需求自己通過整除和求模之類的方法來設定。這個是偽隨機數,只要隨機因子相同就能得到相同的隨機數,所以查詢時也可以很方便。

除留餘數法:這是個最常用,最有用,和最容易理解的。一般的用法是:關鍵字 mod 表長(或者小於表長的某個數)。

例:21、33、4、12、49、50、、、、、、、、

假設表長為10。關鍵字 mod 表長

:1、3、4、2、9、0

這種方法容易產生衝突碰撞,一般對關鍵字mod 質數(一定要小於表長)。

總結:其實上面的一些構造雜湊表的方法可以混用,只要根據思路靈活變通就能構造出很好的雜湊函式。

不管雜湊函式設計的如何的好,當關鍵字越多時,越容易出現衝突碰撞現象。下面介紹下處理碰撞現象的方法,從大方面講2種方法。

第一種:開發定址法。hash = ( hash(key) + d(n)  ) mod p, n = 1,2,3,4,,,,p(p <=  表長);

線性探測:d(n) = 1,2,3,4,5,,,,,當雜湊出來的儲存空間上已經有元素了,那就往該空間的下乙個空間上查詢是否為空的,依次往下找,直到找到空位置,然後存放起來。

平方探測:d(n) = 1^2、2^2、3^2、、、、 方法和線性探測一樣,只是該方法一次性跳轉的空間距離比較大。

偽隨機法:跳轉隨機個位置然後檢視是否為空位置,以此類推,直到找到空位置,然後存放起來。

這個方法如果遇到聚集(元素不均勻的儲存在同一塊區域)那整個演算法的效能都會下降。因為,雜湊到的位址有元素占用,且元素成塊儲存,則+1、、、、、、直到+到很大的乙個數才能找到空位置。後面插入的元素將很可能更難找到空位置。若這個雜湊表很大那查詢的次數將會更大。這種情況下,偽隨機法 》 平方探測 》 線性探測,線性探測是最差的。

第二種:鍊錶法。把碰撞的元素做成個鍊錶節點,一直往後鏈結,形成鍊錶。通俗的講是陣列鍊錶。這是個比較常用的方法。思想和雜湊桶比較類似。後面會附有鍊錶法的程式。

其他的方法有雙雜湊,再雜湊之類的方法。

雜湊演算法的時間複雜度一般是o(1),但如果有處理衝突碰撞的現象則時間複雜度會大些可能達到o(n)。這根據三個方面的原因來考慮:1.雜湊函式設計的是否合理;2.衝突碰撞處理方法設計的是否合理;3.雜湊表的裝載因子是否過大。

前兩種上面已經分析過,現在來看下裝載因子。

裝載因子

=  全部需要填入表中的元素(所有關鍵字) / 雜湊表的長度;

從公式可以看出當裝載因子越大時,表明需要裝載的關鍵字越接近雜湊表的長度(為1時,表明需要裝載的關鍵字和表長度一樣大。也所以裝載因子不能大於1,最大是等於1),也越容易發生衝突碰撞事件。一般規定裝載因子大小在0.7左右,大於這個值時,可以考慮再增加下表的長度,當然這要在雜湊函式和碰撞處理方法都與表長無關的前提下。這個裝載因子在用開放定址法的時候非常有用,因為這個因子直接影響到處理碰撞方法的優劣。

實現**程式見

:hlist雜湊鍊錶的實現--c**實現

hlist 雜湊鍊錶

linux鍊錶設計者 因為 list.h 沒有署名,所以很可能就是 linus torvalds 認為雙頭 next prev 的雙鏈表對於 hash 表來說 過於浪費 因而另行設計了一套用於 hash 表應用的hlist資料結構 單指標表頭雙迴圈鍊錶,從上圖可以看出,hlist的表頭僅有乙個指向首...

hlist雜湊鍊錶

原文出處 http blog.chinaunix.net u 12592 showart.php?id 451619 王耀 wangyao cs.hit.edu.cn hlist雜湊鍊錶是核心中常用的乙個資料結構,由於它不同於普通的鍊錶,所以這裡對hlist雜湊鍊錶進行一下分析,希望對大家有所幫助。...

雜湊鍊錶hlist

zyd cu ydzhang.blog.chinaunix.net 鍊錶 list 和雜湊表 hlist 是核心常用到的兩個工具,負責組織核心中很多的資料結構,如在程序管理中用於組織程序,檔案系統中的inode節點鍊錶,dentry鍊錶,vfsmount鍊錶等等。鍊錶使用struct list he...