算法圖解之散列表

 1. 散列函數

散列函數就是將輸入映射到數字。它必須知足兩個條件:編程

  1. 輸出必須一致,每次輸出同一個key,都應獲得一樣的value。
  2. 將不一樣的輸入映射到不一樣的數字,也就是不能輸入什麼key都獲得一樣的value。

以下圖所示:數組

 

 

 

 

 

 

 散列函數能夠準確的指出價格的存儲位置,具體緣由以下:緩存

  • 散列函數老是將一樣的輸入映射到相同的索引。也就是說apple永遠在第四個格子上
  • 散列函數將不一樣的輸入映射到不一樣的索引。apple的索引爲3,milk的索引爲0
  • 散列函數知道數組有多大,只返回有效的索引

2. 應用案例

1. 手機內置的電話簿服務器

2. DNS解析,網址對應IP地址數據結構

3. 防止重複的一些場景,好比投票、領獎app

4. 緩存。好比說Facebook,它會把常常訪問但又不須要動態傳遞數據的網頁的數據儲存在散列表中,好比about、註冊、登錄頁面。當你訪問Facebook的頁面時,它首先檢查散列表中是否存儲了這些頁面。這樣能夠大大下降服務器的壓力,並且好的散列的運行時間是O(1),效率比去服務器拿數據要快得多。編程語言

 

3. 衝突

衝突就是給兩個或多個鍵分配的位置相同。若是咱們按字母表,給散列函數26個位置,那麼相同開頭的字母就會佔據同一個位置,以下圖:函數

 

這會比一開始將全部元素儲存到一個鏈表中還慢。性能

總結:

1. 要想辦法把散列函數的鍵均勻地映射到散列表的不一樣位置。3d

2.若是散列表存儲的鏈表很長,散列表的速度將急劇降低。然而,若是使用的散列函數很 好,這些鏈表就不會很長!

3. 散列函數很重要,好的散列函數不多致使衝突。

 

4. 性能

在平均狀況下,散列表的查找速度與數組同樣快,而插入和刪除速度與鏈表同樣快,所以它兼具二者的優勢。但在最糟狀況下,散列表的各類操做的速度都很慢。

避免最糟糕狀況的關鍵是避免衝突,這須要:

  1. 較低的填裝因子
  2. 良好的散列函數

4.1 填裝因子

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

 

一個經驗規則是填裝因子一旦大於0.7,就須要調整散列表的長度(resizing),一般將數組增加一倍,而後使用函數hash將全部的元素都插入到新的散列表中。

4.2 良好的散列函數

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

 

糟糕的散列函數讓值扎推,致使大量的衝突

 

 

5.總結

通常的編程語言都實現了散列列表,並且可以得到平均狀況下的性能(包括Python):常量時間,O(1)

 

散列表是一種功能強大的數據結構,其操做速度快,還能讓你以不一樣的方式創建數據模型。你可能很快會發現本身常常在使用它。

  • 你能夠結合散列函數和數組來建立散列表。
  • 衝突很糟糕,你應使用能夠最大限度減小衝突的散列函數。
  • 散列表的查找、插入和刪除速度都很是快。
  • 散列表適合用於模擬映射關係。
  • 一旦填裝因子超過0.7,就該調整散列表的長度。
  • 散列表可用於緩存數據(例如,在Web服務器上)。
  • 散列表很是適合用於防止重複。
相關文章
相關標籤/搜索