stl的hashtable底層實現

2021-07-05 13:30:53 字數 1990 閱讀 7200

hashtable在c++的stl裡佔據著比較重要的一席之地。其中的hash_set、hash_map、hash_multiset、hash_multimap四個關聯容器都是以hashtable為底層實現方法(技巧)。應該說,上述的四個關聯式容器提供的api都是對hashtable原生態api的高層封裝,因為hashtable本身都提供了它們所需要的基礎api。接下來,說說自己對hashtable實現技巧的理解和總結吧!

hashtable底層實現是通過開鏈法來實現的,hash table**內的元素稱為桶(bucket),而由桶所鏈結的元素稱為節點(node),其中存入桶元素的容器為stl本身很重要的一種序列式容器——vector容器。之所以選擇vector為存放桶元素的基礎容器,主要是因為vector容器本身具有動態擴容能力,無需人工干預。而節點元素為自定義的結構體:

template

struct __hashtable_node{   

__hashtable_node* next;

value val; };

可以看到,這本身就是一種很典型的鏈式列表元素的表示方法,通過當前節點,我們可以很方便地通過節點自身的next指標來獲取下一鏈結節點元素。

在hashtable的實現過程中,我們會認識到乙個專有名詞:負載係數(loading factor),意指元素個數除以**大小。很顯然,通過開鏈法,負載係數會大於1。同樣在開鏈方法中,用於裝載桶元素的vector容器大小恆定為乙個質數大小,在具體實現中表現為28個從小到大的28個質數,如:53、97、193、389。。。等等。每次重新分配vector容器大小時,總是將新容器大小設定為第乙個大於當前需要的新容器大小的質數值(上述28個質數中的其中乙個)。接下來,我們來談談hashtable中幾個比較重要的原生態api的實現原理吧。具體的實現技巧建議檢視stl原始碼。

resize(...)方法:此api主要用於判斷當前裝載桶元素的vector容器是否需要重建(或者說是擴容),api的唯一引數即為當前桶元素所鏈結所有節點個數,即鍊錶節點個數(包括當前桶元素),假定為new_num。將new_num值與當前裝載桶元素vector容器的大小進行比較,如果大於則進行容器擴容,依次將所有的節點元素都根據其本身的hash值放置到新的容器對應的桶元素所在的鍊錶中,每次都是從頭部進入插入操作,如果小於或者等於,則直接插入到其本身屬於的桶元素所在的鍊錶頭部中。從中我們可以看到每個桶元素所在的鍊錶的元素個數最多為裝載桶元素的vector容器的容量。否則就要進行重建工作。

insert_unique_noresize(...)方法:此api主要用於往hashtable中插入新值,同時新值不允許重複,否則就不插入,立刻返回。事實上,在正式開始執行此方法之前,首先需要執行前乙個api:resize()方法,確定vector容器是否需要重建。需要的話則執行,否則再是執行當前api。原理很簡單,第一步,根據待插入的新值執行內建函式:bkt_num(new_value),此方法主要是用於確定當前新值歸屬於哪個桶元素所在的鍊錶中,方便之後插入操作。獲取其所在的桶元素之後,依次遍歷當前桶元素所在的鍊錶,檢查是否有與待插入的新值重複的元素,如果有,則直接退出當前函式,如果沒有,則將待插入的新值插入當前鍊錶的頭部,完成新值的插入過程。

insert_equal(...)方法與insert_unique_noresize()原理類似,唯一不同的地方只是可以插入重複值,即若發現相同值,則直接將待插入新值插入到當前節點的後面即可。否則仍然插入到當前鍊錶的頭部位置。**到這裡,想必大家都已經知道呢,hashtable內建的api實現方式並不是很複雜,無非主要是對鍊錶的操作,比如查詢、插入,刪除等操作。像clear(...)函式實現方式也主要就是依次刪除各個桶元素所在的鍊錶中的節點元素即可。

經過上述分析和總結,可以看到,雖然stl本身實現很複雜,但是其實裡面真正的實現細節並非我們大多數人想像的那樣不可理解,只要大家敢於跨出第一步(**原始碼的第一步),相信離真像就會越來越近。最後,以《stl 原始碼剖析》一書前言的一句經典結束今天的hashtable的探索之旅吧!——原始碼之前,了無秘密!與大家共勉吧!

HashTable底層實現

hashtable是繼承與dictionary類,實現了map介面,hashtable的主體還是entry陣列 hashtable的預設容量大小為11,負載因子為0.75 hashtable的主要方法的原始碼實現邏輯,與hashmap中非常相似,有一點重大區別就是所有的操作都是通過synchroni...

STL底層實現

1.vector 底層資料結構為陣列 支援快速隨機訪問 2.list 底層資料結構為雙向鍊錶,支援快速增刪 3.deque 底層資料結構為乙個 控制器和多個緩衝區,詳細見stl原始碼剖析p146,支援首尾 中間不能 快速增刪,也支援隨機訪問 deque是乙個雙端佇列 double ended que...

STL的底層實現機制

1.vector 底層資料結構為陣列 支援快速隨機訪問 2.list 底層資料結構為雙向鍊錶,支援快速增刪 3.deque 底層資料結構為乙個 控制器和多個緩衝區,詳細見stl原始碼剖析p146,支援首尾 中間不能 快速增刪,也支援隨機訪問 deque是乙個雙端佇列 double ended que...