程式碼隨想錄:雜湊表
前言
- 雜湊表是通過關鍵碼的值而進行直接訪問的資料結構
- 陣列也是一張hash表,只不過陣列的關鍵碼就是他的下標,或者說是索引
- hash表最強大就在於它可以快速判斷一個元素是否在一個集合裡面,時間複雜度$O(1)$
- hash方法&hash函式
在密碼學裡,雜湊函式是指對一串訊息做計算,根據one-way-function得到一個訊息摘要,確保原訊息的真實性
將一個數據列表對映倒hash表上,就涉及了hash function,即雜湊函式
雜湊函式,把學生的姓名直接對映為雜湊表上的索引,然後就可以通過查詢索引下標快速知道這位同學是否在這所學校裡了。
雜湊函式如下圖所示,通過hashCode把名字轉化為數值,一般hashcode是通過特定編碼方式,可以將其他資料格式轉化為不同的數值,這樣就把學生名字對映為雜湊表上的索引數字了。
很顯然有個問題,雜湊碰撞
避免hash碰撞的方法
-
- 拉鍊法
- 發生衝突的位置搞一個連結串列,有衝突的元素放在連結串列裡
- 拉鍊法
-
-
- 拉鍊法就是要選擇適當的雜湊表的大小,這樣既不會因為陣列空值而浪費大量記憶體,也不會因為連結串列太長而在查詢上浪費太多時間
- 線性探測法
- 保證tableSize大於dataSize。 我們需要依靠雜湊表中的空位來解決碰撞問題。
- 當出現碰撞時候後來的元素插到碰撞位置後面的空閒位置
-
- hash表常用的幾種資料結構
- array 陣列
- set 集合
- map 對映
- C++中set及其底層實現
std::unordered_set底層實現為雜湊表,std::set 和std::multiset 的底層實現是紅黑樹,紅黑樹是一種平衡二叉搜尋樹,所以key值是有序的,但key不可以修改
- 所以當我們要使用集合來解決hash問題時,優先使用unorderwd_set
- 如果集合要是有序的,就使用set
- 如果集合不僅要是有序的,還要有重複元素,就使用multiset
- C++中map及其底層實現
std::unordered_map 底層實現為雜湊表,std::map 和std::multimap 的底層實現是紅黑樹。同理,std::map 和std::multimap 的key也是有序的
map 是一個key - value 的資料結構,map中,對key是有限制,對value沒有限制的,因為key的儲存方式使用紅黑樹實現的。
- 為什麼都說set和map是雜湊法使用的資料結構?
雖然std::set、std::multiset 的底層實現是紅黑樹,不是雜湊表,但是std::set、std::multiset 依然使用雜湊函式來做對映,只不過底層的符號表使用了紅黑樹來儲存資料,所以使用這些資料結構來解決對映問題的方法,我們依然稱之為雜湊法。 map也是一樣的道理。
- hash_set hash_map與unordered_set,unordered_map有什麼關係?
unordered_set,unordered_map是C++標準庫中的資料結構,而hash_set hash_map是民間高手自發造的車輪子,其實是一個東西,既然標準都有了,還是用標準裡面的東西吧!
- 雜湊法也是犧牲了空間換取了時間,因為要使用額外的陣列,set或者是map來存放資料,才能實現快速的查詢
- 當要判斷一個元素是否在集合裡,就可以考慮hash表