今天我們來介紹乙個新的資料結構:雜湊表(hash table),平時也叫
「雜湊表」或
「hash表」
。雜湊錶用的是陣列支援按照下標隨機訪問資料的特性,所以雜湊表其實就是陣列的一種擴充套件,由陣列演化而來。
下面用個例子來介紹一下。
假如我們有89名選手參加學校運動會。為了方便記錄成績,每個選手都有乙個參賽號碼,依次是1到
89。其中,參賽選手的編號叫作鍵(key)或者關鍵字。把參賽編號轉化為陣列下標的對映方法叫作雜湊函式(或者「hash函式」,
「雜湊函式
」),而雜湊函式計算得到的值就叫作雜湊值(或「hash值」,
「雜湊值」)
雜湊函式
雜湊函式,顧名思意,它是乙個函式。可以定義成hash(key),其中key表示元素的鍵值,
hash(key)
的值表示經過雜湊函式計算得到的雜湊值。
該如何構造雜湊函式呢?有三個基本要求:
1. 雜湊函式計算得到的雜湊值是乙個非負整數;
2. 如果
key1 = key2
,那hash(key1)==hash(key2)
;3. 如果
key1 ≠ key2
,那hash(key1) ≠ hash(key2)
。雜湊衝突
雜湊函式基本不可能做到不同的key對應的雜湊值都不一樣,這種就叫作雜湊衝突。即便是
md5、
sha、
crc等雜湊演算法也無法避免。
常用的雜湊衝突解決方法有兩類:開放定址法(open addressing)和鍊錶法(
chaining
)。開放定址法
開放定址法的核心思想是,如果出現雜湊衝突,就重新找乙個空間位置,將其插入。
雜湊表跟陣列一樣,不僅支援插入、查詢操作,還支援刪除操作。對於使用線性探測法解決衝突的雜湊表,刪除操作有些特別,要將刪除的元素,標記為deleted。當線性探測查詢的時候,遇到標記為
deleted
的空間,並不停下,而是繼續往下探測。
線性探測法存在很大問題,當雜湊表中插入的資料越來越多,雜湊衝突發生的可能性也越來越大,空閒位置越來越少,線性探測的時間也就越來越久。極端情況下,可能需要探測整個雜湊表,所以最壞情況的時間複雜度是o(n)。
對於開放定址衝突解決方法,除了線性探測方法外,還有兩種比較經典的探測方法:二次探測和雙重雜湊。
為了盡可能保證雜湊表的操作效率,一般情況下會盡可能保證雜湊表中有一定比例的空閒槽位。我們用裝載因子(load factor)
鍊錶法
鍊錶法是一種更加常用的雜湊衝突解決辦法,相比開放定址法,要更加簡單。
在雜湊表中,每個「桶(
bucket)」
或「槽(slot)」
對應一條鍊錶,所有雜湊值相同的元素都放在相同的槽位對應的鍊錶中。
插入:通過雜湊函式計算出對應的雜湊槽位,將其插入到對應的鍊錶中。時間複雜度o(1)
查詢、刪除:同樣通過雜湊函式找到對應的槽,然後遍歷鍊錶查詢或者刪除。時間複雜度跟鍊錶的長度k成正比,也就是
o(k)
。課後思考
1. 假設我們有
10萬條
url訪問日誌,如何按照訪問次數給
url排序?
遍歷 10 萬條資料,以
url
為 key
,訪問次數為
value
,存入雜湊表,同時記錄下訪問次數的最大值
k,時間複雜度
o(n)
。如果 k 不是很大,可以使用桶排序,時間複雜度
o(n)
。如果 k 非常大(比如大於
10 萬),就使用快速排序,複雜度
o(nlogn)
。2. 有兩個字元串陣列,每個陣列大約有
10萬條字元串,如何快速找出兩個陣列中相同的字元串?
遍歷兩個字串陣列,以字串為key,訪問次數為
value
,存入雜湊表。然後遍歷雜湊表找出
value>1
的字串。
資料結構與演算法之美 鍊錶
如何優雅的寫出鍊錶 6大學習技巧 一 理解指標或引用的含義1.含義 將某個變數 物件 賦值給指標 引用 實際上就是就是將這個變數 物件 的位址賦值給指標 引用 2.示例 p next q 表示p節點的後繼指標儲存了q節點的記憶體位址。p next p next next 表示p節點的後繼指標儲存了p...
資料結構與演算法之美 鍊錶
1.如何實現lru快取淘汰演算法 答 回答這個問題之前,我們首先了解一下什麼是快取 2.鍊錶的三種形式 單鏈表 雙向鍊錶 迴圈鍊錶 簡介一下單鏈表 頭節點用於記錄基位址,有了它我們就可以遍歷整條鍊錶,而尾節點特殊地方不是指向下乙個節點,而是指向乙個空位址。鍊錶因為不是乙個連續的位址,所以不需要考慮連...
資料結構與演算法之美
什麼是資料結構?什麼是演算法 狹義重點 複雜度分析 方法 邊學邊練,適度刷題 複雜度分析 時間複雜度 常見時間複雜度 非多項式量級 非常低效的演算法 空間複雜度 漸進空間複雜度,表示演算法的儲存空間和資料規模的增長關係 最好情況時間複雜度 理想情況的時間複雜度 最壞情況時間複雜度 最糟糕的情況下的時...