1. 程式人生 > >java中的雜湊演算法和hashcode深入講解

java中的雜湊演算法和hashcode深入講解

java中的雜湊演算法和hashcode深入講解

一,雜湊演算法的概念

    在計算機領域,雜湊演算法具有非常廣泛的應用,比如快速查詢和加密。今天我們來討論一下雜湊演算法。我們先從理論知識開始。

1,什麼是雜湊演算法
    百科中,從雜湊演算法的功能上,對雜湊演算法進行了定義。百科是這樣定義雜湊演算法的:雜湊演算法可以將任意長度的二進位制值對映
為較短的,固定長度的二進位制值。我們把這個二進位制值成為雜湊值。


2,雜湊值的特點
  * 雜湊值是二進位制值;
  * 雜湊值具有一定的唯一性;

  * 雜湊值極其緊湊;
  * 要找到生成同一個雜湊值的2個不同輸入,在一定時間範圍內,是不可能的。

    正因為雜湊值的這些特點,使得雜湊演算法應用在加密領域成為可能。雜湊演算法在加密領域的應用,源於雜湊演算法的不可逆性,對於
使用者輸入的密碼,通過雜湊演算法可以得到一個雜湊值。並且,同一個密碼,生成的雜湊值總是相等的。這樣,伺服器就可以在不知道
使用者輸入的密碼的情況下,判斷使用者輸入的密碼是否正確。

3,雜湊表
    雜湊表是一種資料機構。雜湊表根據關鍵字(key),生成關鍵字的雜湊值,然後通過雜湊值對映關鍵字對應的值。雜湊表儲存了多

餘的key(我們本可以只儲存值的),是一種用空間換時間的做法。在記憶體足夠的情況下,這種“空間換時間”的做法是值得的。雜湊表的
產生,靈感來源於陣列。我們知道,陣列號稱查詢效率最高的資料結構,因為不管陣列的容量多大,查詢的時間複雜度都是O(1)。如果
所有的key都是不重複的整數,那麼這就完美了,不需要新增一張雜湊表,來做關鍵字(key)到值(value)的對映。但是,如果key是
字串,情況就不一樣了。我們必須要來建一張雜湊表,進行對映。
    資料庫索引的原理,其實和雜湊表是相同的。資料庫索引也是用空間換時間的做法。

二,雜湊演算法的具體實現


    雜湊演算法在不同的語言,具有不同的實現。這裡我們以java語言為例來進行說明。

1,雜湊演算法在HashMap類中的應用
    java中的集合,比如HashMap/Hashtable/HashSet等,在實現時,都用到了雜湊演算法。當我們向容器中新增元素時,我們有必要知道
這個元素是否已經存在。
    從實現上來說,java是藉助hashcode()方法和equals()方法來實現判斷元素是否已經存在的。當我們向HashMap中插入元素A時,首先,
呼叫hashcode()方法,判斷元素A在容器中是否已經存在。如果A元素的hashcode值在HashMap中不存在,則直接插入。否則,接著呼叫
equals()方法,判斷A元素在容器中是否已經存在。hashcode()的時間複雜度為O(1),equals()方法的時間複雜度為O(m),整體的時間複雜度
就是:O(1) + O(m)。其中,m是桶的深度。桶的深度是一個什麼概念呢,桶的深度是指具有相同hashcode值得元素的個數,也就是發生雜湊
碰撞的元素的個數。
    一個好的雜湊演算法應該儘量減少雜湊碰撞的次數。

2,雜湊演算法在String類中的應用

    Sring類重寫了Object類的equals()方法和hashcode()方法。hashcode()方法的原始碼如下:

[java]  view plain  copy
  1. public int hashCode() {  
  2. int h = hash;  
  3. if (h == 0) {  
  4.     int off = offset;  
  5.     char val[] = value;  
  6.     int len = count;  
  7.   
  8.         for (int i = 0; i < len; i++) {  
  9.             h = 31*h + val[off++];  
  10.         }  
  11.         hash = h;  
  12.     }  
  13.     return h;  
  14. }  

    原始碼寫的比較簡潔,閱讀起來也不是太方便,下面我詳細解讀一下:
// String類的hashcode值(雜湊值)是如何計算得到的?具體實現?為了方便閱讀,我們來進行分步說明

[java]  view plain  copy
  1. static void hashcodeTest(){  
  2.       
  3.     String str = "yangcq";  
  4.       
  5.     // 第一步 = (int)'y'  
  6.     // 第二步 = (31 * (int)'y') + (int)'a'  
  7.     // 第三步 = 31 * ((31 * (int)'y') + (int)'a') + (int)'n'  
  8.     // 第四步 = 31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g'  
  9.     // 第五步 = 31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c'  
  10.     // 第六步 = 31 * (31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c') + (int)'q'  
  11.       
  12.     // 上面的過程,也可以用下面的方式表示  
  13.       
  14.     // 第一步 = (int)'y'  
  15.     // 第二步 = 31 * (第一步的計算結果) + (int)'a'  
  16.     // 第三步 = 31 * (第二步的計算結果) + (int)'n'  
  17.     // 第四步 = 31 * (第三步的計算結果) + (int)'g'  
  18.     // 第五步 = 31 * (第四步的計算結果) + (int)'c'  
  19.     // 第六步 = 31 * (第五步的計算結果) + (int)'q'  
  20.       
  21.     int hashcode = 31 * (31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c') + (int)'q';  
  22.     System.out.println("yangcq的hashcode = " + hashcode);        // yangcq的hashcode = -737879313  
  23.     System.out.println("yangcq的hashcode = " + str.hashCode());  // yangcq的hashcode = -737879313  
  24.       
  25. }  

    通過上面的測試方法,我們可以很清晰的看到hashcode()方法具體的計算過程。下面再貼上2個類,一個是自己寫的測試類
MyHashcode.java,另一個是HashcodeOfString.java

[java]  view plain  copy
  1. /** 
  2.  * java中物件的hashcode值,是如何計算得到的。 
  3.  */  
  4. public class MyHashcode {  
  5.       
  6.     /** The value is used for character storage. */  
  7.     static char value[];  
  8.   
  9.     /** The offset is the first index of the storage that is used. */  
  10.     static int offset;  
  11.   
  12.     /** The count is the number of characters in the String. */  
  13.     static int count;  
  14.   
  15.     /** Cache the hash code for the string */  
  16.     static int hash; // Default to 0  
  17.   
  18.     /** 
  19.      * @param args 
  20.      */  
  21.     public static void main(String[] args) {  
  22.         // TODO Auto-generated method stub  
  23.         String str1 = new String("yangcq");  
  24.         String str2 = new String("yangcq");  
  25.         // 如果2個字串的內容相同,那麼這2個字串的hashcode必然相同  
  26.         System.out.println(new String("yangcq").hashCode() == new String("yangcq").hashCode());  
  27.         System.out.println(str1.hashCode() == str2.hashCode());  
  28.           
  29.         System.out.println(str1.hashCode());  
  30.         System.out.println(hashCode1(str1));  
  31.           
  32.         // 測試自定義的hashcode方法  
  33.         HashcodeOfString hashcodeOfString = new HashcodeOfString();  
  34.         hashcodeOfString.hashCode(str1);  
  35.         System.out.println("str1的hashcode = " + hashcodeOfString.hashCode(str1));  
  36.         System.out.println("str1的hashcode = " + str1.hashCode());  
  37.     }  
  38.       
  39.     // HashMap中實現的hash演算法(再hash演算法)  
  40.     static int hash(int h) {  
  41.         // This function ensures that hashCodes that differ only by  
  42.         // constant multiples at each bit position have a bounded  
  43.         // number of collisions (approximately 8 at default load factor).  
  44.         h ^= (h >>> 20) ^ (h >>> 12);  
  45.         return h ^ (h >>> 7) ^ (h >>> 4);  
  46.     }  
  47.       
  48.     // String類實現的hashcode方法原始碼  
  49.     static int hashCode1(String str) {  
  50.         int h = hash;  
  51.         if (h == 0) {  
  52.             int off = 0;  
  53.             char val[] = str.toCharArray();  
  54.             int len = str.length();  
  55.   
  56.             for (int i = 0; i < len; i++) {  
  57.                 h = 31 * h + val[off++];  
  58.             }  
  59.             hash = h;  
  60.         }  
  61.         return h;  
  62.     }  
  63.       
  64.     // String類的hashcode值(雜湊值)是如何計算得到的?具體實現?為了方便閱讀,我們來進行分步說明  
  65.     static void hashcodeTest(){  
  66.           
  67.         String str = "yangcq";  
  68.           
  69.         // 第一步 = (int)'y'  
  70.         // 第二步 = (31 * (int)'y') + (int)'a'  
  71.         // 第三步 = 31 * ((31 * (int)'y') + (int)'a') + (int)'n'  
  72.         // 第四步 = 31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g'  
  73.         // 第五步 = 31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c'  
  74.         // 第六步 = 31 * (31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c') + (int)'q'  
  75.           
  76.         // 上面的過程,也可以用下面的方式表示  
  77.           
  78.         // 第一步 = (int)'y'  
  79.         // 第二步 = 31 * (第一步的計算結果) + (int)'a'  
  80.         // 第三步 = 31 * (第二步的計算結果) + (int)'n'  
  81.         // 第四步 = 31 * (第三步的計算結果) + (int)'g'  
  82. 相關推薦

    java演算法hashcode深入講解

    java中的雜湊演算法和hashcode深入講解 一,雜湊演算法的概念     在計算機領域,雜湊演算法具有非常廣泛的應用,比如快速查詢和加密。今天我們來討論一下雜湊演算法。我們先從理論知識開始。 1,什麼是雜湊演算法  &

    java遞迴演算法漢諾塔

    java中,一個方法呼叫它自身,被稱為方法遞迴。方法遞迴中包含了一種隱藏式的迴圈。它會重複執行某段程式碼,而且不需要迴圈語句控制。 例如有如下數學題。已知一個數列:f(0) =1 、f(1)=4、f(n+2) =2*f(n+1) + f(n),其中n是大於0的整數,求f(1

    hashcodeequals及演算法理解

    因為會設計到很多equal的知識,所以先深入理解一下equals(). 1.equals() Object類中的預設equals()方法和==是沒有區別的,都是判斷兩個物件是否指向同一個引用,記憶體地址是否相同,即是否就是一個物件。而string類和integer等,都需要重寫equals()方

    python 表應用,常見函式 MD5SHA2演算法

    通過雜湊函式計算資料儲存 insert(key, value) 插入鍵值對 get(key) 獲取值 delete(key) 刪除值 常見雜湊函式 除法雜湊:h(k) = k % m 乘法雜湊:h(k) = floor(m*(

    java實現 SHA1 安全演算法

    博主人很懶,直接就貼程式碼了~~ import java.security.MessageDigest; /**  * 安全雜湊演算法 SHA1  * @author lenovo  *  */ p

    深入理解Java的fail-fastfail-safe

    什麼是快速失敗(fail-fast)和安全失敗(fail-safe)?它們又和什麼內容有關係。以上兩點就是這篇文章的內容,廢話不多話,正文請慢用。 我們都接觸 HashMap、ArrayList 這些集合類,這些在 java.util 包的集合類就都是快速失敗的;而  java.ut

    https是如何加密的 (知道了原理之後,希望自己能用程式碼實現一下,還有用於對個人資訊公鑰進行加密的演算法,有時間也去查一下)

    由於http協議是明文傳輸資料,資料的安全性沒有保障。為了改進這種明文傳輸協議,https誕生了。   https是在應用層和傳輸層之間,增加了一層ssl加密。對於加密,請往下看:   1、對稱加密   每次在傳送資料之前,伺服器先生成一把金鑰,

    深入理解hashmap(三)二叉搜尋樹的恩怨情仇

    前面兩篇文章介紹了hashmap的原始碼和理論,今天把剩餘的部分紅黑樹講一下。理解好紅黑樹,對我們後續對hashmap或者其他資料結構的理解都是很有好處的。比方說為什麼後面jdk要把hashmap中的單鏈表更新成紅黑樹? 要理解紅黑樹首先要弄清楚普通二叉樹的一些基本概念 父節點和子節點,這個我就不多說了。

    data_structure_and_algorithm -- 演算法(下):演算法在分散式系統有哪些應用?

    今天主要看一下雜湊演算法的應用(二),主要參考:前谷歌工程師王爭的課程,感興趣可以通過下面方式微信掃碼購買: 你可能已經發現,這三個應用都跟分散式系統有關。沒錯,今天我就帶你看下,雜湊演算法是如何解決這些分散式問題的。 應用五:負載均衡 我們知道,負載均衡演算法

    圖片相似度判斷-差異值演算法JAVA

    差異值雜湊演算法(dHash) 圖片縮放為9*8大小 將圖片灰度化 差異值計算(每行相鄰畫素的差值,這樣會生成8*8的差值,前一個畫素大於後一個畫素則為1,否則為0) 生成雜湊值 package com.example.demo.hello; import jav

    一致性演算法原理及其在分散式系統的應用

    分散式快取問題 假設我們有一個網站,最近發現隨著流量增加,伺服器壓力越來越大,之前直接讀寫資料庫的方式不太給力了,於是我們想引入Memcached作為快取機制。現在我們一共有三臺機器可以作為Memcached伺服器,如下圖所示。 很顯然,最簡單的策略是將每一次Memcached請求隨機發送到一臺Memca

    equals()HashCode()深入理解以及Hash演算法原理

    1.深入理解equals(): 在我的一篇部落格“==”和.equals()的區別中向讀者提出提醒: Object類中的equals方法和“==”是一樣的,沒有區別,即倆個物件的比較是比較他們的棧記憶體中儲存的記憶體地址。而String類,Integer類等等一些類,是

    Java表的運用,判斷一個數組是否存在相同的元素之間的距離在k以內!

    Check if a given array contains duplicate elements within k distance from each other 用雜湊表,複雜度O(n),

    對等網路主流分散式演算法比較分析(轉載)

    本文首先從P2P的定義出發,介紹了結構化P2P與非結構化P2P的區別以及結構化P2P的核心技術DHT。而後,本文深入介紹了幾種主流的DHT演算法與協議並對每種協議進行了討論。文章的最後展望了DHT在未來的發展趨勢。 對 等網路(Peer-to-Peer,簡稱P2P)是目前非

    equalsHashCode深入理解以及Hash演算法原理

    equals()和HashCode()深入理解以及Hash演算法原理 1.深入理解equals(): 在我的一篇部落格“==”和.equals()的區別中向讀者提出提醒: Object類中的e

    一致性演算法在分散式場景的應用

    文章概要 本文將會從實際應用場景出發,介紹一致性雜湊演算法(Consistent Hashing)及其在分散式系統中的應用。首先本文會描述一個在日常開發中經常會遇到的問題場景,藉此介紹一致性雜湊演算法以及這個演算法如何解決此問題;接下來會對這個演算法進行相對詳細的描述,並討論一些如虛擬節

    查詢--深入理解一致性演算法

    注:本篇部落格只是講述了一致性雜湊的思想,我們會在之後講述分散式雜湊表以及一致性雜湊的一種實現(Chord演算法)。 什麼是一致性雜湊演算法? 引用自維基百科: 一致性雜湊是一種特殊的雜湊演算法。在使用一致雜湊演算法後,雜湊表槽位數(大小)的改變

    由HashMap演算法引出的求餘%與運算&轉換問題

    目錄 回到頂部 1、引出問題   在前面講解 HashMap  的原始碼實現時,有如下幾點:   ①、初始容量為 1<<4,也就是24 = 16      ②、負載因子是0.75,當存入HashMap的元素佔比超過整個容量的75%時,進行擴容,而且

    Java基礎之加解密(三) SHA安全演算法

    介紹:安全雜湊演算法(Secure Hash Algorithm)主要適用於數字簽名標準(Digital Signature Standard DSS)裡面定義的數字簽名演算法(Digital Signature Algorithm DSA)。該演算法的思想是接收一段明文,

    c++演算法實現

    /* 雜湊演算法的實現原理是: 通過獲得你要排序的序列長度(m), 然後得出比這個 m 大的素數作為陣列的長度(n), 然後對接下來的輸入資料(D)進行取模運算(v=D%n), 然後