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- public int hashCode() {
- int h = hash;
- if (h == 0) {
- int off = offset;
- char val[] = value;
- int len = count;
- for (int i = 0; i < len; i++) {
- h = 31*h + val[off++];
- }
- hash = h;
- }
- return h;
- }
原始碼寫的比較簡潔,閱讀起來也不是太方便,下面我詳細解讀一下:
// String類的hashcode值(雜湊值)是如何計算得到的?具體實現?為了方便閱讀,我們來進行分步說明 [java] view plain copy
- static void hashcodeTest(){
- String str = "yangcq";
- // 第一步 = (int)'y'
- // 第二步 = (31 * (int)'y') + (int)'a'
- // 第三步 = 31 * ((31 * (int)'y') + (int)'a') + (int)'n'
- // 第四步 = 31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g'
- // 第五步 = 31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c'
- // 第六步 = 31 * (31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c') + (int)'q'
- // 上面的過程,也可以用下面的方式表示
- // 第一步 = (int)'y'
- // 第二步 = 31 * (第一步的計算結果) + (int)'a'
- // 第三步 = 31 * (第二步的計算結果) + (int)'n'
- // 第四步 = 31 * (第三步的計算結果) + (int)'g'
- // 第五步 = 31 * (第四步的計算結果) + (int)'c'
- // 第六步 = 31 * (第五步的計算結果) + (int)'q'
- int hashcode = 31 * (31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c') + (int)'q';
- System.out.println("yangcq的hashcode = " + hashcode); // yangcq的hashcode = -737879313
- System.out.println("yangcq的hashcode = " + str.hashCode()); // yangcq的hashcode = -737879313
- }
通過上面的測試方法,我們可以很清晰的看到hashcode()方法具體的計算過程。下面再貼上2個類,一個是自己寫的測試類
MyHashcode.java,另一個是HashcodeOfString.java [java] view plain copy
- /**
- * java中物件的hashcode值,是如何計算得到的。
- */
- public class MyHashcode {
- /** The value is used for character storage. */
- static char value[];
- /** The offset is the first index of the storage that is used. */
- static int offset;
- /** The count is the number of characters in the String. */
- static int count;
- /** Cache the hash code for the string */
- static int hash; // Default to 0
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- String str1 = new String("yangcq");
- String str2 = new String("yangcq");
- // 如果2個字串的內容相同,那麼這2個字串的hashcode必然相同
- System.out.println(new String("yangcq").hashCode() == new String("yangcq").hashCode());
- System.out.println(str1.hashCode() == str2.hashCode());
- System.out.println(str1.hashCode());
- System.out.println(hashCode1(str1));
- // 測試自定義的hashcode方法
- HashcodeOfString hashcodeOfString = new HashcodeOfString();
- hashcodeOfString.hashCode(str1);
- System.out.println("str1的hashcode = " + hashcodeOfString.hashCode(str1));
- System.out.println("str1的hashcode = " + str1.hashCode());
- }
- // HashMap中實現的hash演算法(再hash演算法)
- static int hash(int h) {
- // This function ensures that hashCodes that differ only by
- // constant multiples at each bit position have a bounded
- // number of collisions (approximately 8 at default load factor).
- h ^= (h >>> 20) ^ (h >>> 12);
- return h ^ (h >>> 7) ^ (h >>> 4);
- }
- // String類實現的hashcode方法原始碼
- static int hashCode1(String str) {
- int h = hash;
- if (h == 0) {
- int off = 0;
- char val[] = str.toCharArray();
- int len = str.length();
- for (int i = 0; i < len; i++) {
- h = 31 * h + val[off++];
- }
- hash = h;
- }
- return h;
- }
- // String類的hashcode值(雜湊值)是如何計算得到的?具體實現?為了方便閱讀,我們來進行分步說明
- static void hashcodeTest(){
- String str = "yangcq";
- // 第一步 = (int)'y'
- // 第二步 = (31 * (int)'y') + (int)'a'
- // 第三步 = 31 * ((31 * (int)'y') + (int)'a') + (int)'n'
- // 第四步 = 31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g'
- // 第五步 = 31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c'
- // 第六步 = 31 * (31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c') + (int)'q'
- // 上面的過程,也可以用下面的方式表示
- // 第一步 = (int)'y'
- // 第二步 = 31 * (第一步的計算結果) + (int)'a'
- // 第三步 = 31 * (第二步的計算結果) + (int)'n'
- // 第四步 = 31 * (第三步的計算結果) + (int)'g'
-
相關推薦
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
hashcode和equals及雜湊演算法理解
因為會設計到很多equal的知識,所以先深入理解一下equals(). 1.equals() Object類中的預設equals()方法和==是沒有區別的,都是判斷兩個物件是否指向同一個引用,記憶體地址是否相同,即是否就是一個物件。而string類和integer等,都需要重寫equals()方
python中 雜湊表應用,常見函式 MD5和SHA2演算法
通過雜湊函式計算資料儲存 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-fast和fail-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)是目前非
equals和HashCode深入理解以及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), 然後