重溫數據結構:哈希 哈希函數 哈希表

點擊查看 Java 集合框架深刻理解 系列, - ( ゜- ゜)つロ 乾杯~

在學習 HashMap 前,咱們先來溫習下 Hash(哈希) 的概念。html


什麼是 Hash

Hash(哈希),又稱「散列」。java

散列(hash)英文原意是「混雜」、「拼湊」、「從新表述」的意思。web

在某種程度上,散列是與排序相反的一種操做,排序是將集合中的元素按照某種方式好比字典順序排列在一塊兒,而散列經過計算哈希值,打破元素之間原有的關係,使集合中的元素按照散列函數的分類進行排列。算法

在介紹一些集合時,咱們總強調須要重寫某個類的 equlas() 方法和 hashCode() 方法,確保惟一性。這裏的 hashCode() 表示的是對當前對象的惟一標示。計算 hashCode 的過程就稱做 哈希。數組

爲何要有 Hash

咱們一般使用數組或者鏈表來存儲元素,一旦存儲的內容數量特別多,須要佔用很大的空間,並且在查找某個元素是否存在的過程當中,數組和鏈表都須要挨個循環比較,而經過 哈希 計算,能夠大大減小比較次數緩存

這裏寫圖片描述

舉個栗子:

如今有 4 個數 {2,5,9,13},須要查找 13 是否存在。服務器

1.使用數組存儲,須要新建個數組 new int[]{2,5,9,13},而後須要寫個循環遍歷查找:

int[] numbers = new int[]{2,5,9,13};
    for (int i = 0; i < numbers.length; i++) {
        if (numbers[i] == 13){
            System.out.println("find it!");
            return;
        }
    }

這樣須要遍歷 4 次才能找到,時間複雜度爲 O(n)。markdown

2.而假如存儲時先使用哈希函數進行計算,這裏我隨便用個函數:

H[key] = key % 3;

四個數 {2,5,9,13} 對應的哈希值爲:網絡

H[2] = 2 % 3 = 2;
 H[5] = 5 % 3 = 2;
 H[9] = 9 % 3 = 0;
 H[13] = 13 % 3 = 1;

而後把它們存儲到對應的位置。數據結構

當要查找 13 時,只要先使用哈希函數計算它的位置,而後去那個位置查看是否存在就行了,本例中只需查找一次,時間複雜度爲 O(1)。

所以能夠發現,哈希 實際上是隨機存儲的一種優化,先進行分類,而後查找時按照這個對象的分類去找。

哈希經過一次計算大幅度縮小查找範圍,天然比從所有數據裏查找速度要快。

好比你和我同樣是個剁手族買書狂,家裏書一大堆,若是書存放時不分類直接擺到書架上(數組存儲),找某本書時可能須要腦殼從左往右從上往下轉好幾圈才能發現;若是存放時按照類別分開放,技術書、小說、文學等等分開(按照某種哈希函數計算),找書時只要從它對應的分類裏找,天然省事多了。

哈希函數

哈希的過程當中須要使用哈希函數進行計算。

哈希函數是一種映射關係,根據數據的關鍵詞 key ,經過必定的函數關係,計算出該元素存儲位置的函數。

表示爲:

address = H [key]

幾種常見的哈希函數(散列函數)構造方法

  • 直接定址法
    • 取關鍵字或關鍵字的某個線性函數值爲散列地址。
    • 即 H(key) = key 或 H(key) = a*key + b,其中a和b爲常數。
    • 好比這裏寫圖片描述
  • 除留餘數法
    • 取關鍵字被某個不大於散列表長度 m 的數 p 求餘,獲得的做爲散列地址。
    • 即 H(key) = key % p, p < m。
    • 好比這裏寫圖片描述
  • 數字分析法
    • 當關鍵字的位數大於地址的位數,對關鍵字的各位分佈進行分析,選出分佈均勻的任意幾位做爲散列地址。
    • 僅適用於全部關鍵字都已知的狀況下,根據實際應用肯定要選取的部分,儘可能避免發生衝突。
    • 好比 這裏寫圖片描述
  • 平方取中法
    • 先計算出關鍵字值的平方,而後取平方值中間幾位做爲散列地址。
    • 隨機分佈的關鍵字,獲得的散列地址也是隨機分佈的。
    • 好比 這裏寫圖片描述
  • 摺疊法(疊加法)
    • 將關鍵字分爲位數相同的幾部分,而後取這幾部分的疊加和(捨去進位)做爲散列地址。
    • 用於關鍵字位數較多,而且關鍵字中每一位上數字分佈大體均勻。
    • 好比 這裏寫圖片描述
  • 隨機數法
    • 選擇一個隨機函數,把關鍵字的隨機函數值做爲它的哈希值。
    • 一般當關鍵字的長度不等時用這種方法。

構造哈希函數的方法不少,實際工做中要根據不一樣的狀況選擇合適的方法,總的原則是儘量少的產生衝突

一般考慮的因素有關鍵字的長度分佈狀況哈希值的範圍等。

如:當關鍵字是整數類型時就能夠用除留餘數法;若是關鍵字是小數類型,選擇隨機數法會比較好。

哈希衝突的解決

選用哈希函數計算哈希值時,可能不一樣的 key 會獲得相同的結果,一個地址怎麼存放多個數據呢?這就是衝突。

經常使用的主要有兩種方法解決衝突:

1.連接法(拉鍊法)

拉鍊法解決衝突的作法是:
將全部關鍵字爲同義詞的結點連接在同一個單鏈表中。

若選定的散列表長度爲 m,則可將散列表定義爲一個由 m 個頭指針組成的指針數組 T[0..m-1] 。

凡是散列地址爲 i 的結點,均插入到以 T[i] 爲頭指針的單鏈表中。
T 中各份量的初值均應爲空指針。

在拉鍊法中,裝填因子 α 能夠大於 1,但通常均取 α ≤ 1。

這裏寫圖片描述

2.開放定址法

用開放定址法解決衝突的作法是:

用開放定址法解決衝突的作法是:當衝突發生時,使用某種探測技術在散列表中造成一個探測序列。沿此序列逐個單元地查找,直到找到給定的關鍵字,或者碰到一個開放的地址(即該地址單元爲空)爲止(若要插入,在探查到開放的地址,則可將待插入的新結點存人該地址單元)。查找時探測到開放的地址則代表表中無待查的關鍵字,即查找失敗。

簡單的說:當衝突發生時,使用某種探查(亦稱探測)技術在散列表中尋找下一個空的散列地址,只要散列表足夠大,空的散列地址總能找到

按照造成探查序列的方法不一樣,可將開放定址法區分爲線性探查法、二次探查法、雙重散列法等。

a.線性探查法

hi=(h(key)+i) % m ,0 ≤ i ≤ m-1

基本思想是:
探查時從地址 d 開始,首先探查 T[d],而後依次探查 T[d+1],…,直到 T[m-1],此後又循環到 T[0],T[1],…,直到探查到 有空餘地址 或者到 T[d-1]爲止。

b.二次探查法

hi=(h(key)+i*i) % m,0 ≤ i ≤ m-1

基本思想是:
探查時從地址 d 開始,首先探查 T[d],而後依次探查 T[d+1^2],T[d+2^2],T[d+3^2],…,等,直到探查到 有空餘地址 或者到 T[d-1]爲止。

缺點是沒法探查到整個散列空間。

c.雙重散列法

hi=(h(key)+i*h1(key)) % m,0 ≤ i ≤ m-1

基本思想是:
探查時從地址 d 開始,首先探查 T[d],而後依次探查 T[d+h1(d)], T[d + 2*h1(d)],…,等。

該方法使用了兩個散列函數 h(key) 和 h1(key),故也稱爲雙散列函數探查法。

定義 h1(key) 的方法較多,但不管採用什麼方法定義,都必須使 h1(key) 的值和 m 互素,才能使發生衝突的同義詞地址均勻地分佈在整個表中,不然可能形成同義詞地址的循環計算。

該方法是開放定址法中最好的方法之一。

哈希的應用

  • 哈希表
  • 分佈式緩存

哈希表(散列表)

哈希表(hash table)是哈希函數最主要的應用。

哈希表是實現關聯數組(associative array)的一種數據結構,普遍應用於實現數據的快速查找。

這裏寫圖片描述

用哈希函數計算關鍵字的哈希值(hash value),經過哈希值這個索引就能夠找到關鍵字的存儲位置,即桶(bucket)。哈希表不一樣於二叉樹、棧、序列的數據結構通常狀況下,在哈希表上的插入、查找、刪除等操做的時間複雜度是 O(1)。

查找過程當中,關鍵字的比較次數,取決於產生衝突的多少,產生的衝突少,查找效率就高,產生的衝突多,查找效率就低。所以,影響產生衝突多少的因素,也就是影響查找效率的因素。
影響產生衝突多少有如下三個因素:

  1. 哈希函數是否均勻;
  2. 處理衝突的方法;
  3. 哈希表的加載因子。

哈希表的加載因子和容量決定了在何時桶數(存儲位置)不夠,須要從新哈希。

加載因子太大的話桶太多,遍歷時效率變低;太大的話頻繁 rehash,致使性能下降。因此加載因子的大小須要結合時間和空間效率考慮。

在 HashMap 中的加載因子爲 0.75,即四分之三。

分佈式緩存

網絡環境下的分佈式緩存系統通常基於一致性哈希(Consistent hashing)。簡單的說,一致性哈希將哈希值取值空間組織成一個虛擬的環,各個服務器與數據關鍵字K使用相同的哈希函數映射到這個環上,數據會存儲在它順時針「遊走」遇到的第一個服務器。可使每一個服務器節點的負載相對均衡,很大程度上避免資源的浪費。

在動態分佈式緩存系統中,哈希算法的設計是關鍵點。使用分佈更合理的算法可使得多個服務節點間的負載相對均衡,能夠很大程度上避免資源的浪費以及部分服務器過載。 使用帶虛擬節點的一致性哈希算法,能夠有效地下降服務硬件環境變化帶來的數據遷移代價和風險,從而使分佈式緩存系統更加高效穩定。

Thanks

http://www.nowamagic.net/librarys/veda/detail/1273

http://blog.csdn.net/cywosp/article/details/23397179/

http://www.cnblogs.com/qiaoshanzi/p/5295554.html

http://baike.baidu.com/view/549615.htm

https://books.google.co.jp/books?id=wCWmdhdX1AYC&pg=PA214&lpg=PA214&dq=%E6%95%B0%E5%AD%97%E5%88%86%E6%9E%90%E6%B3%95&source=bl&ots=5ieOT99Dob&sig=UcYbua2lwYocCQr32HF0XDF34h4&hl=zh-CN&sa=X&ved=0ahUKEwj104zw__fPAhUDw7wKHf3cAhIQ6AEISzAJ#v=onepage&q=%E6%95%B0%E5%AD%97%E5%88%86%E6%9E%90%E6%B3%95&f=false

http://sjjp.tjuci.edu.cn/sjjg/DataStructure/DS/web/chazhao/chazhao9.4.3.3.htm

http://www.cnblogs.com/qiaoshanzi/p/5295554.html

相關文章
相關標籤/搜索