詞典 二 雜湊表 Hash table

2022-08-28 18:51:07 字數 3191 閱讀 1245

雜湊表(hashtable)是一種高效的詞典結構,可以在期望的常數時間內實現對詞典的所有介面的操作。雜湊完全摒棄了關鍵碼有序的條件,所以可以突破cba式演算法的複雜度界限。

雜湊表邏輯上,有一系列可以存放詞條的單元(桶)組成。各個桶按照邏輯次序,在物理上也應當是連續的,因而,可以採用陣列來實現,雜湊表也可以稱為桶陣列。合法的秩空間[0,r)也可以稱作位址空間。

雜湊函式

雜湊,即為關鍵碼空間到桶位址空間的對映,hash():key->hash(key)

假設學號為2013300000-2013303999,乙個長度為4000的雜湊表a[0-3999],只需要hash(key)=key-2013300000,即可實現沒有空餘也沒有重複的雜湊,稱為完美雜湊。

實際上,完美雜湊是非常困難的,比如,乙個**號碼為7位,而乙個單位的**為幾千個,此時按照這種對映,仍然需要10^7次方規模的桶陣列。定義裝填因子為非空桶/桶的總數,此時的利用率非常低。

(1)除餘法:hash(key)=key mod m。顯然,如此簡單的策略會造成很大的問題,隨機性並不好而且容易衝突。

(2)mad法:multiple-add-divide,hash(key)=(a*key+b) mod m。可以看到,除餘法是a=1,b=0的特例。相當於是一種線性方法。

(3)數字分析法:從key的特定進製展開中取出特定的若干位。

還有平方取中法、摺疊法異或法等...實現的時候為了簡單,可以採用隨機數法,不過不同的語言和平台隨機數的實現方式可能不同,需謹慎。

1 templateclass hashtable :public dictionary2

18bool

put(k k, v v);

19 v* get

(k k);

20bool

remove(k k);

21 };

雜湊表的實現,內部主要是維護乙個桶陣列,外部介面即為詞典的介面。

1 templatehashtable::hashtable(intc)2

9int primenlt(int c, int n, std::string file)//

查詢素數

10

這裡實現的策略,是從事先計算好的檔案中選取乙個素數作為桶的初始數量。

1 templatehashtable::~hashtable()

2

析構函式要注意,釋放掉非空的桶以及用來標記的點陣圖結構。

衝突

雜湊表的乙個很大問題,就是衝突。因為雜湊的基本思想,就是通過快速把key轉換為乙個秩,從而可以迅速進行查詢、插入和刪除這樣的詞典操作。但是,即使把桶陣列設定地非常大,或者選擇特別合適的雜湊函式,也非常有可能造成衝突,即hash(key1)=hash(key2)。此時,後乙個詞條插入的時候,對應的已經被占用了。因此,必須採用一種辦法,化解這種衝突。常見的衝突排解方法有幾種:

(1)多槽位法。把一組衝突的詞條設定為乙個小規模的詞典,分別存放在對應的桶單元中。一種簡單的方法,把每個桶細分為小的槽位,比如用向量或者列表來實現。這種方法的缺陷顯而易見,很多槽位是空著的,利用率很低。

(2)獨立鏈法。與多槽位法類似,不過把每組衝突的詞條組織為乙個鍊錶的形式。這種方法的缺點在於,查詢衝突的時候需要遍歷整個鍊錶。

(3)公共溢位區法。在原來的雜湊之外另設定乙個詞典,插入衝突時就轉存到其中。

閉雜湊

說了那麼多,最後還是要採用一種別的方法0 0閉雜湊的方法,就是充分利用雜湊表中的空桶,桶位址對於雜湊中的其他桶是開放的,雜湊內部與外界是封閉的。具體地,採用查詢鏈的方法。最簡單的就是線性試探,每次衝突的時候,在後繼中查詢最近的空桶,第i次試探的桶單元為(hash(key)+i) mod m。這種方法也存在較大的缺陷,容易區域性聚集從而加長查詢的長度,可以採用平方試探法等方法改進。

這種線性查詢的方法,可能會因為多個相鄰的衝突詞條,而產生彼此的交替,在這種情況下,查詢的長度也會增大。如果刪除了其中的元素,查詢鏈會斷裂,從而影響到其他詞條的查詢。一種解決的辦法是懶惰刪除,即刪除乙個元素後,用位圖結構來標記,刪除掉實際的詞條。這樣,在實際的查詢過程中,無論桶是否空,只要標記存在,就可以繼續向下進行查詢。基於線性試探的策略如下:

1 templatev* hashtable::get

(k k)

26 templateint hashtable::probe4hit(const k& k)//

尋找匹配的桶

713 templatebool hashtable::remove(k k)

14

對於插入操作,需要先尋找乙個合適的空桶,如果沒有空桶,那麼需要重新分配乙個雜湊表。為了保證效率,規定裝填因子不超過1/2。

1 templatebool hashtable::put(k k, v v)

29 templateint hashtable::probe4free(const k&k)

1015 templatevoid hashtable::rehash()

16

rehash()的策略並不複雜,其實就是重新分配乙個陣列,並把原來的陣列轉移到其中,再釋放掉之前的陣列。

最後,因為key不可能總數整數,因此,需要把char double long等等型別轉換為hashcode,方法有很多,在此不表0 0

在介紹理論的最後0 0雜湊函式的選擇以閉策略的選擇都有很多,其實只要弄懂雜湊的思想以及實現就可以了,細節的方法,各種語言都有自己的雜湊表,甚至好多種...

雜湊的應用

沒刷過題,就先搬運下書上的幾個例子吧。

桶排序

桶排序可以打破cba式排序理論上nlogn的界限。通過雜湊的策略,通過獨立鏈構建方法,即可實現基於雜湊的排序。具體操作,即使用最簡單的雜湊函式hash(key)=key,把數字存入相應的桶,然後再從頭到尾輸出桶陣列即可。只需要遍歷數字一遍,常數時間計算hash(key),再遍歷輸出一遍即可,複雜度為o(n)。

基數排序

假設一組詞條採用字典序等方式排序,比如英文詞典。這時,只需要用多趟桶排序即可完成。具體地,從優先順序最低的位開始進行桶排序,排序後的結果再按照優先順序的順序,知道最後一趟排序完,結果即為所需。具體的證明就忽略了...複雜度為o(t*(n+m)),其中m為各個欄位的取值範圍的最大值,t為趟數。

hash table 雜湊表(雜湊表)

hash table 也叫雜湊表。涉及到雜湊函式 雜湊衝突處理的問題。雜湊函式是雜湊表的關鍵,是用來從值到雜湊表索引 存放位置 的對映。比如 要存放乙個學校學生的姓名,他們是amanda,jack,andy,tom,bob,black等等500個人。我們可以設計乙個雜湊表,容量為500,來存放這些學...

HashTable 雜湊表(雜湊表)

雜湊表 雜湊表 是根據關鍵字 key 而訪問在記憶體位置的資料結構。其方法是 它通過乙個關鍵值的函式將所需的資料對映到表中的位置來訪問資料,這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表 雜湊表 構造雜湊表的幾種方法 直接定址法 取關鍵字的某個線性函式為雜湊位址,hash key key 或 h...

HashTable雜湊表 雜湊表(雜湊桶)

處理雜湊衝突的開鏈法 拉鍊法 雜湊桶 使用素數做雜湊表的長度,可以降低雜湊衝突 素數表size t getnextprime size t num 素數表 雜湊桶的節點的定義 template struct hashnode 在插入前檢查容量,以及負載因子。不夠就進行增容,按素數表進行增,以減小雜湊...