算法圖解(五)|散列表與字典

我們之前介紹過簡單查找和二分查找,簡單查找是從頭開始一個個查找,二分查找是在有序列表中按分而治之的思想進行查找,雖然二分查找已經很快速了,但是在有些情況下,還是不能達到人們的需求。

例如我們去商店買東西,如果售貨員是通過本子記錄價格,即使記錄是有序的,可以進行二分查找,在查找價格時,都能感覺到顧客的怒氣。因此我們更希望售貨員可以記住每樣商品的價格,我們將商品拿給他,他立馬就能報出價格,付款之後很快就可以離開。

這種複雜度爲O(1)的算法結構如何實現呢?

散列表

算法圖解第五章內容學習筆記

5.1 散列函數

特點:無論輸入是什麼數據,散列函數都輸出一個數字。用專業術語來說明,散列函數“將輸入映射到數字”。

散列函數將輸入映射爲數字,這有何用途呢?

這可以構建一個記住所有商品價格的售貨員。你給他一個商品名字,他能立即報給你商品的價格。我們來根據散列函數來構建散列表。

一句話解釋:商品價格存儲在一個列表中,將商品名字輸入散列函數,函數輸出該商品存儲在列表中的序號,根據序號讀取商品價格。

首先創建一個空數組

在這個數組中存儲商品的價格。下面來將蘋果的價格加入到這個數組中。爲此,將apple作爲輸入交給散列函數。

散列函數的輸出爲3,因此我們將蘋果的價格存儲到數組的索引3處。

下面將牛奶(milk)的價格存儲到數組中。爲此,將milk作爲散列函數的輸入。

散列函數的輸出爲0,我們便將牛奶的價格存儲在索引0處。

不斷地重複這個過程,最終整個數組將填滿價格。

現在假設需要知道鱷梨(avocado)的價格。你無需在數組中查找,只需將avocado作爲輸入

交給散列函數。

它將告訴你鱷梨的價格存儲在索引4處。果然,你在那裏找到了。

函數特點:

(1)散列函數總是將同樣的輸入映射到相同的結果。

(2)散列函數將不同的輸入映射到不同的索引。

(3)散列函數知道數組有多大,只返回有效的索引,不會超出索引。

實現:

不用考慮實現,在任意的一門語言中都有散列表的實現,我們僅需要直接使用就好,例如散列表在python中的實現成爲字典,下面是一個字典的使用例子。

5.2 應用案例

(1) 將散列表用於查找

電話號碼查找,給一個名字,輸出他的號碼。

(2)防止重複(投票時防止重複投票)

(3)將散列表用作緩存

5.3 衝突

上面的敘述中,我們說到,散列函數總是將不同的鍵映射到數組的不同位置。實際上,幾乎不可能編寫出這樣的散列函數。

例如我們存儲商品單價,若採用按字母表順序分配數組的位置的散列函數。如下圖:

如果你要將蘋果apple的價格存儲到散列表中,分配給你的是第一個位置。後來再遇到存儲鱷梨的價格時,又是以A開頭,按理說應該分配第一個位置給它。但是這裏,第一個位置已經存儲了蘋果的價格了,這就引發了“衝突”

解決方法:

如果兩個鍵映射到了同一個位置,就在這個位置存儲一個鏈表

但如果,所有的商品都以A開頭,如下圖,這就是散列表最糟糕的情況。這時速度會很慢,因此需要避免這種情況。

經驗:

(1)散列函數很重要。最理想的情況是,散列函數將鍵均勻地映射到散列表的不同位置。最糟糕的情況是將所有的鍵都映射到一個位置;

(2)如果散列表存儲的鏈表很長,散列表的速度將急劇下降。然而,如果使用的散列函數很好,這些鏈表就不會很長!

5.4 性能

散列表的性能常數級別複雜度:

在平均情況下,散列表的查找(獲取給定索引處的值)速度與數組一樣快,而插入和刪除速度與鏈表一樣快,因此它兼具兩者的優點!但在最糟情況下,散列表的各種操作的速度都很慢。因此,在使用散列表時,避開最糟情況至關重要。爲此,需要避免衝突。而要避免衝突,需要有:

(1)較低的填裝因子;

(2)良好的散列函數。

5.4.1 填裝因子

	裝填因子 = 散列表包含的元素數目/位置總數

填裝因子越低,發生衝突的可能性越小,散列表的性能越高。一個不錯的經驗規則是:一旦填裝因子大於0.7,就調整散列表的長度。

調整散列表的長度:首先創建一個更長的新數組,通常將數組增長一倍,再使用函數hash將所有的元素都插入到這個新的散列表中。

調整散列表長度的工作需要很長時間!但平均而言,即便考慮到調整長度所需的時間,散列表操作所需的時間也爲O(1)。

5.4.2 良好的散列函數

良好的散列函數讓數組中的值呈均勻分佈。

糟糕的散列函數讓值扎堆,導致大量的衝突。

總結:

(1)散列表是一種功能強大的數據結構,其操作速度快,還能讓你以不同的方式建立數據模型。

(2)散列表的查找、插入和刪除速度都非常快。

(3)一旦填裝因子超過0.7,就該調整散列表的長度。

(4)使用可以最大限度減少衝突的散列函數避免衝突。

(5)散列表適合用於模擬映射關係,可用於緩存數據、防止重複。

《算法圖解》第五章散列表(字典)學習筆記,下一章“廣度優先搜索”

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章