1. 程式人生 > >雜湊桶的預分配記憶體的實現形式

雜湊桶的預分配記憶體的實現形式

之前在書本中使用過的hashtable的時候,總體思想是使用一大片記憶體,然後把key值hash成一個int,找到對應的記憶體的結構的位置,然後找到相應的資料。常用的解決衝突的方式是,需要進行拉鍊,再new一個新結點來表示資料。這是一種實現形式,邏輯上沒有什麼問題。

總體方案如下圖所示(圖片非原創)

存在問題:

大部分情況下,都需要通過動態分配記憶體的方式進行拉鍊。而對於類似共享記憶體,或者是堆記憶體,預先規劃好一片固定大小的記憶體的場景下,這種實現方式,無法滿足,而且需要動態建立和釋放記憶體,效率較低。

改進方案:

對於一片固定大小的儲存空間,先從邏輯上劃分成兩個區域,一個是meta區,即是原來邏輯上的孔位,另一個是hashnode資料區,直正存放資料。

1、metadata區,也是按照業務需求,劃分成N個連續儲存的結構體。

2、對於hashnode區域,也同時也是劃分成M個連續儲存的資料結構體。

3、資料區中,使用1個雙向鏈對節點資源進行管理。初始化的時候,空閒連結串列把所有的節點串聯起來。

4、查詢key操作:

pos = hash(key),通過pos找到metadata中對應的medata資訊,通過meta資訊,找到資料區中的索引值index,通過index即可找到對應的資料鏈的起始節點。通過遍歷對應的連結串列即可找到對應的key的資料。

5、插入操作:

先通過pos=hash(key),查詢是否已經分配過對應key的資料區。如果已經分配過,則覆蓋寫操作。

如果未找到,則通過空閒連結串列中,表頭分配一個空閒節點作為資料儲存空間,把資料寫到hashnode中,並把分配的節點ID,記到pos對應的metadata資料中。並把該節點通過前插法,插入到該pos對應的資料鏈中,即是拉鍊的過程。

6、刪除操作:

通過pos=hash(key),查詢到對應的metadata資訊,通過metadata中儲存的索引,查詢到資料區的起始節點。通過遍歷資料鏈,找到對應的資料節點,把該節點從雙向連結串列中刪除,把把該節點,加入到空閒連結串列中。

總結:

這種方式實現的hash,有兩個優點:

1)一是避免了動態記憶體的分配與釋放,都是比較快的操作。

2)預分配的節點,在使用過程中,能夠達到比較高的利用率,只要還存在空閒節點,該hast桶中就能再存放資料。