散列表(哈希表)

概述

什麼是散列表? 若是提及它的另外一個名字, 你必定很熟悉, 它的英文叫"Hash Table", 哈希表, 很熟悉吧. 算法

散列的思想, 其實就是利用數組的隨機訪問特性, 將key-value形式的數據, 其中的key轉換成數組下標, 便可實現將其存放到數組中, 進而實現隨機訪問. 數組

而其中將key轉換成數字的函數, 被稱爲散列函數, 或哈希函數. 函數

爲了方便你們看, 如下統一稱爲哈希, 知道這倆是一回事就行. 性能

哈希函數

設計一個哈希函數, 有以下三點要求: spa

  1. 散列函數計算得出的值是一個正整數(數組下標嘛)設計

  2. 若key相等, 則計算後的哈希值相等code

  3. 若key不相等, 則計算後的哈希值不相等對象

後面兩點, 說白了就是, 計算後的哈希值是惟一的, 不變的. hash

要想達到第二點要求, 應該不難, 只要算法固定, 輸入與輸出就應該是固定的嘛it

可是, 要想實現第三點, 就不同了, 要想找到一個徹底符合的, 幾乎是不可能. 並且, 要想將其放到數組中, 數組的大小是有限的啊, 因此, 當出現計算後兩個哈希值相等的狀況, 就是哈希衝突.

哈希衝突

既然沒有完美的哈希函數, 那麼就不可避免會發生哈希衝突, 那麼就要解決哈希衝突, 經常使用的有開放尋址法和鏈表法.

1. 開放尋址法

開放尋址法的思想很簡單, 當發生哈希衝突的狀況時, 就從當前位置日後找, 找到第一個空缺的位置放入.

對於開放尋址法, 查找操做也瓜熟蒂落, 計算key的哈希值後, 查看其下標元素是否爲要尋找的元素, 若不是, 向後尋找, 一直找到出現空位, 則說明key不在表中.

可是, 刪除操做就比較麻煩了, 由於查找是經過空位來判斷的, 若直接刪除key, 就會在下次查找時出現空位而打斷原本應該繼續的查找. 對於這種狀況, 咱們能夠將刪除的空位標記爲delete, 查找時遇到delete不會中斷就行了.

上面說的這種查找方法叫線性探測法, 顧名思義, 就是一個一個日後找, 另外還有兩種經典查找方法: 二次探測和雙重散列.

二次探測: 線性探測每次探測的步長(每次日後找的個數)是1, 也就是說探測的下標是k+0,k+1,k+2,k+3. 二次探測就是每次訪問的步長變爲原來的二次, 探測的下標爲: k+0,k+1,k+2,k+9

雙重散列: 就是不僅僅使用一個哈希函數, 而是使用一串, 當第一個哈希函數發生衝突時, 就用第二個計算, 再衝突, 再用第三個計算, 直到找到空位

問題

很明顯, 開放尋址法有很大的問題. 當表中數據愈來愈多的時候, 哈希衝突的機率也會愈來愈大, 對應的查找操做也就會愈來愈慢, 甚至最終會遍歷整個表.

裝載因子

用裝載因子來表示哈希表中空位的多少, 其計算公式是:

裝載因子=表中元素個數 / 表的長度

裝載因子越大, 說明空位越少, 衝突越多, 哈希表的性能越低.

2. 鏈表法

使用鏈表法來解決哈希衝突相對來講更爲常見一些, Java中的HashMap就是這麼處理的.

經過一張圖來簡單說明鏈表的處理方法:

當發生哈希衝突時, 將數據插入到對應的鏈表中. Java中的HashMap就是經過hashcode方法計算數組下標, 再經過equals方法判斷兩對象是否相等.

相關文章
相關標籤/搜索