什么是Hash
Hash,也可以稱為“散列”,就是把任意長度的輸入,通過散列算法,變換成固定長度的輸出,該輸出就是散列值。這是一種壓縮映射,也就是,散列值的空間通常遠小於輸入的空間,不同的輸入可能會散列成相同的輸出(也就是多對一的關系)。
哈希表的構造
在所有的線性數據結構中,數組的定位速度最快,因為它可通過數組下標直接定位到相應的數組空間,就不需要一個個查找。而哈希表就是利用數組這個能夠快速定位數據的結構解決以上的問題的。
"數組可以通過下標直接定位到相應的空間”,對就是這句,哈希表的做法其實很簡單,就是把Key通過一 個固定的算法函數既所謂的哈希函數轉換成一個整型數字,然后就將該數字對數組長度進行取余,取余結果就當作數組的下標,將value存儲在以該數字為下標 的數組空間里,而當使用哈希表進行查詢的時候,就是再次使用哈希函數將key轉換為對應的數組下標,並定位到該空間獲取value,如此一來,就可以充分 利用到數組的定位性能進行數據定位。
通過關鍵字除以槽數m將關鍵字映射到槽里的方法。哈希函數是H(k)=k Mod m。
舉個例子,m=12,k=100,H(100)=4。
而如果m=2k,那么無論k是什么,H(K)的值都是一個0和奇數,也即是說只要奇數槽和0槽被占用,其他的偶數槽都是浪費掉了。如果m=2^r,那么H(k)的值就是k的低r位(化成二進制)。這樣造成的后果是某一個槽有很多的關鍵字。所以來說一般的m取值盡量不要接近2的整數冪,而且還要是質數。
雖然我們不希望發生沖突(同一個key有多個value),但實際上發生沖突的可能性仍是存在的。當關鍵字值域遠大於哈希表的長度,而且事先並不知道關鍵字的具體取值時。沖突就難免會發生。另外,當關鍵字的實際取值大於哈希表的長度時,而且表中已裝滿了記錄,如果插入一個新記錄,不僅發生沖突,而且還會發生溢出。因此,處理沖突和溢出是哈希技術中的兩個重要問題。一般有開放地址法、鏈地址法。
適用范圍
快速查找,刪除的基本數據結構,通常需要總數據量可以放入內存。
什么是Map
Map是c++標准庫STL提供的一類關聯式容器,提供key-value的存儲和查找功能。
Map是基於紅黑樹的(同樣set也是),那么它的查找速度是log(n)級別的。
它的優點是占用內存小。
Hash與Map的區別
權衡三個因素: 查找速度, 數據量, 內存使用,可擴展性,有序性。
總體來說,hash查找速度會比RB樹快,而且查找速度基本和數據量大小無關,屬於常數級別;而RB樹的查找速度是log(n)級別。並不一定常數就比log(n) 小,因為hash還有hash函數的耗時。當元素達到一定數量級時,考慮hash。但若你對內存使用特別嚴格, 希望程序盡可能少消耗內存,那么hash可能會讓你陷入尷尬,特別是當你的hash對象特別多時,你就更無法控制了,而且 hash的構造速度較慢。
紅黑樹並不適應所有應用樹的領域。如果數據基本上是靜態的,那么讓他們待在他們能夠插入,並且不影響平衡的地方會具有更好的性能。如果數據完全是靜態的,例如,做一個哈希表,性能可能會更好一些。
在實際的系統中,例如,需要使用動態規則的防火牆系統,使用紅黑樹而不是散列表被實踐證明具有更好的伸縮性。Linux內核在管理vm_area_struct時就是采用了紅黑樹來維護內存塊的。
總結:
紅黑樹是有序的,Hash是無序的,根據需求來選擇。
紅黑樹占用的內存更小(僅需要為其存在的節點分配內存),而Hash事先就應該分配足夠的內存存儲散列表(即使有些槽可能遭棄用)。
紅黑樹查找和刪除的時間復雜度都是O(logn),Hash查找和刪除的時間復雜度都是O(1)。
補充:
如果只需要判斷Map中某個值是否存在之類的操作,當然是Hash實現的要更加高效。
如果是需要將兩個Map求並集交集差集等大量比較操作,就是紅黑樹實現的Map更加高效。
————————————————
版權聲明:本文為CSDN博主「ljlstart」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/ljlstart/article/details/51335687