由HashMap雜湊演算法引出的求餘%和與運算&轉換問題
目錄
1、引出問題
在前面講解 HashMap 的原始碼實現時,有如下幾點:
①、初始容量為 1<<4,也就是24 = 16
②、負載因子是0.75,當存入HashMap的元素佔比超過整個容量的75%時,進行擴容,而且在不超過int型別的範圍時,進行2次冪的擴充套件(指長度擴為原來2倍)
擴大一倍
③、新新增一個元素時,計算這個元素在HashMap中的位置,也就是本篇文章的主角 雜湊運算。分為三步:
第一步:取 hashCode 值: key.hashCode()
第二步:高位參與運算:h>>>16
第三步:取模運算:(n-1) & hash
1 static final int hash(Object key) { 2 int h; 3 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); 4 } 5 6 tab[i = (n - 1) & hash];
ps:第 6 行程式碼是我自己加的。
我們知道一個好的 雜湊演算法能夠使得元素分佈的更加均勻,從而減少雜湊衝突。HashMap 在這塊的處理就很巧妙:
首先第一步取得 hashCode,該方法是一個用native修飾的本地方法,返回的是一個 int 型別的值(根據記憶體地址換算出來的一個值),通常我們都會重寫該方法。
第二步將取得的雜湊值無符號右移16位,高位補0。並與前面第一步獲得的hash碼進行按位異或^ 運算。這是為了當length比較小的時候,也能保證考慮到高低Bit位都參與到Hash的計算中,同時不會有太大的開銷。
本文的重點是第三步,將經過前面兩步獲取的 hash 值,與HashMap的集合長度減 1 進行按位與 & 運算:(n-1) & hash。但是其實很多雜湊演算法,為了使元素分佈均勻,都是用的取模運算,用一個值去模上總長度,即 n%hash。我們知道在計算機中 & 的效率比 % 高很多,那麼如何將 % 轉換為 & 運算呢?在HashMap 中,是用的 (n - 1) & hash 進行運算的,那麼這是為什麼呢?
這就是本篇部落格我們將要明白的問題。
2、結論
我們先給出結論:
當 lenth = 2n 時,X % length = X & (length - 1)
也就是說,長度為2的n次冪時,模運算 % 可以變換為按位與 & 運算。
比如:9 % 4 = 1,9的二進位制是 1001 ,4-1 = 3,3的二進位制是 0011。 9 & 3 = 1001 & 0011 = 0001 = 1
再比如:12 % 8 = 4,12的二進位制是 1100,8-1 = 7,7的二進位制是 0111。12 & 7 = 1100 & 0111 = 0100 = 4
上面兩個例子4和8都是2的n次冪,結論是成立的,那麼當長度不為2的n次冪呢?
比如:9 % 5 = 4,9的二進位制是 1001,5-1 = 4,4的二進位制是0100。9 & 4 = 1001 & 0100 = 0000 = 0。顯然是不成立的。
為什麼是這樣?下面我們來詳細分析。
3、分析過程
首先我們要知道如下規則:
①、"<<" 左移:右邊空出的位上補0,左邊的位將從字頭擠掉,左移一位其值相當於乘2。
②、">>"右移:右邊的位被擠掉,右移一位其值相當於除以2。對於左邊移出的空位,如果是正數則空位補0,若為負數,可能補0或補1,這取決於所用的計算機系統。
③、">>>"無符號右移,右邊的位被擠掉,對於左邊移出的空位一概補上0。
根據二進位制數的特點,相信大家很好理解。
對於給定一個任意的十進位制數XnXn-1Xn-2....X1X0,我們將其用二進位制的表示方法分解:
XnXn-1Xn-2....X1X0 = Xn*2n+Xn-1*2n-1+......+X1*21+X0*20 3-1公式
這裡的十進位制數只有三位,同理當有N位時,後面2的冪次方依次從 0 開始遞增到 N 。
回到上面的結論: lenth = 2n 時,X % length = X & (length - 1)
以及對於除法,被除數是滿足分配率的(除數不滿足):
成立:(a+b)÷c=a÷c+b÷c 3-2公式
不成立:a÷(b+c)≠a÷c+b÷c
通過 3-1公式以及 3-2 公式,我們可以得出當任意一個十進位制除以一個2k的數時,我們可以將這個十進位制轉換成3-1公式的表示形式:
(XnXn-1Xn-2....X1X0) / 2k = (Xn*2n+Xn-1*2n-1+......+X1*21+X0*20) / 2k = Xn*2n / 2k +Xn-1*2n-1 / 2k +......+ X1*21 / 2k + X0*20 / 2k
如果我們想求上面公式的餘數,相信大家一眼就能看出來:
①、當 0<= k <= n 時,餘數為 Xk*2k+Xk-1*2k-1+......+X1*21+X0*20 ,也就是說 比 k 大的 n次冪,我們都舍掉了(大的都能整除 2k),比k小的我們都留下來了(小的不能整除2k)。那麼留來下來即為餘數。
②、當 k > n 時,餘數即為整個十進位制數。
看到這裡,我們離證明結論已經很近了。再回到上面說的二進位制的移位操作,向右移 n 位,表示除以 2n 次方,由此我們得到一個很重要的結論:
一個十進位制數對一個2n 的數取餘,我們可以將這個十進位制轉換為二進位制數,將這個二進位制數右移n位,移掉的這 n 位數即是餘數。
知道怎麼算餘數了,那麼我們怎麼去獲取這移掉的 n 為數呢?
我們再看20,21,22....2n 用二進位制表示如下:
0001,0010,0100,1000,10000......
我們把上面的數字減一:
0000,0001,0011,0111,01111......
根據與運算子&的規律,當位上都是 1 時,結果才是 1,否則為 0。所以任意一個二進位制數對 2k 取餘時,我們可以將這個二進位制數與(2k-1)進行按位與運算,保留的即使餘數。
這就完美的證明了前面給出的結論:
當 lenth = 2n 時,X % length = X & (length - 1)
注意,一定要是2n次方,才滿足上面的公式,否則就是錯誤的。
4、總結
通過上面的分析過程了,我們完美了證明了公式的正確性。在回到 HashMap 的實現過程,我們知道HashMap的初始容量為啥是 1<<4 了吧,而且每次擴容都是擴大一倍。因為必須要完美的滿足 hash 演算法。
相關推薦
由HashMap雜湊演算法引出的求餘%和與運算&轉換問題
目錄 回到頂部 1、引出問題 在前面講解 HashMap 的原始碼實現時,有如下幾點: ①、初始容量為 1<<4,也就是24 = 16 ②、負載因子是0.75,當存入HashMap的元素佔比超過整個容量的75%時,進行擴容,而且
QMap QHash的選擇(QString這種複雜的比較,雜湊演算法比map快很多)
QMap QHash有近乎相同的功能。很多資料裡面介紹過他們之間的區別了。但是都沒有說明在使用中如何選擇他們。 實際上他們除了儲存順序的差別外,只有key操作的區別。 雜湊演算法是將包含較多資訊的“key”轉換成包含資訊較少的“key的key”。通過“key的key”查詢key,在通過key找到value
java中的雜湊演算法和hashcode深入講解
java中的雜湊演算法和hashcode深入講解 一,雜湊演算法的概念 在計算機領域,雜湊演算法具有非常廣泛的應用,比如快速查詢和加密。今天我們來討論一下雜湊演算法。我們先從理論知識開始。 1,什麼是雜湊演算法 &
密碼學之Hash雜湊演算法
前言 在第一篇文章中已經有介紹區塊鏈技術概念,我們知道區塊鏈主要是由共識演算法機制、p2p網路、密碼學這幾個核心技術組成,前面幾篇文章講了共識演算法,p2p網路,這次我們談一下密碼學,密碼學是區塊鏈系統的基礎,如果沒有密碼學技術支撐,區
據說,80%的人都搞不懂雜湊演算法 區塊鏈 雜湊演算法
本文約9000字+,閱讀(觀看)需要52分鐘 聊到區塊鏈的時候也少不了會聽到“雜湊”、“雜湊函式”、“雜湊演算法”,是不是聽得一頭霧水?別急,這一講我們來講講什麼是雜湊演算法。 雜湊是一種加密演算法 雜湊函式(Hash Function),也稱為雜湊函式或雜湊函式。雜湊函式是一個
hashcode和equals及雜湊演算法理解
因為會設計到很多equal的知識,所以先深入理解一下equals(). 1.equals() Object類中的預設equals()方法和==是沒有區別的,都是判斷兩個物件是否指向同一個引用,記憶體地址是否相同,即是否就是一個物件。而string類和integer等,都需要重寫equals()方
資料結構與演算法之美專欄學習筆記-雜湊演算法
雜湊演算法的定義和原理 將任意長度的二進位制串對映為固定長度的二進位制串。 這個對映的規則就是雜湊演算法,而通過原始資料對映之後得到的二進位制串就是雜湊值。 設計一個優秀的雜湊演算法需要滿足: 從雜湊值不能反向推匯出原始資料(所以雜湊演算法也叫單向雜湊演算法); 對輸入資料非常敏感,哪怕原始
密碼學(對稱與非對稱密碼 雜湊演算法)
目錄 密碼學 密碼學發展 對稱加密體制 非對稱加密體制 混合加密 雜湊演算法 數字簽名過程 密碼學的應用--網站認證 密碼學 密碼學發展 古典密碼:古代----19世紀末 近代密碼:20世紀初---1949年 現代密碼:1949(夏農
<Golang>MD5、SHA256等雜湊演算法介紹、應用場景及具體實現
版權宣告:本文為作者原創,如需轉載,請註明出處https://blog.csdn.net/weixin_42940826 前言 MD5和SHA256是非常常用的兩種單向雜湊函式,雖然MD5在2005年已經被中國密碼學家王小云攻破,但是曾經也是叱吒風雲的被大規模使用,現在
MySQL索引演算法——雜湊演算法
雜湊索引 雜湊索引(hash index)基於雜湊表實現,只有精確匹配索引所有列的查詢才有效。對於每一行資料,儲存引擎都會對所有的索引列計算一個雜湊碼(hash code), 雜湊碼是一個較小的值,並且不同鍵值的行計算出來的雜湊碼也不一樣。雜湊索引將所
https是如何加密的 (知道了原理之後,希望自己能用程式碼實現一下,還有用於對個人資訊和公鑰進行加密的雜湊演算法,有時間也去查一下)
由於http協議是明文傳輸資料,資料的安全性沒有保障。為了改進這種明文傳輸協議,https誕生了。 https是在應用層和傳輸層之間,增加了一層ssl加密。對於加密,請往下看: 1、對稱加密 每次在傳送資料之前,伺服器先生成一把金鑰,
4.4.2 python 字串雙指標/雜湊演算法2 —— Substring with Concatenation of All Words & Group Anagrams
這兩道題目都很巧妙的應用了雜湊演算法,可以作為雜湊演算法的應用講解,後面介紹雜湊的時候就不再做題了哈。 30. Substring with Concatenation of All Words You are given a string, s, and a list of wor
4.4.1 python 字串雙指標/雜湊演算法1—— Reverse Vowels of a String & Longest Substring Without Repeating Char
這一部分開始,我們應用雙指標及雜湊等常見的簡單的演算法,解決一些字串的難題。 345. Reverse Vowels of a String Write a function that takes a string as input and reverse only the vow
資料結構與算法系列16--雜湊演算法
什麼的雜湊演算法? 將任意長度的二進位制值串對映為固定長度的二進位制值串,這個對映的規則就是雜湊演算法。而通過原始資料對映後得到的二進位制值串就是雜湊值。 一個優秀的雜湊演算法應該滿足哪幾點? 從原始資料計算得到的雜湊值,不能反向推匯出原始資料的值。 對輸入的資料非
LeetCode | 你不得不瞭解的雜湊演算法 !
⒈雜湊是什麼 ? 問大家一個問題 。如果手機上儲存了 1000 個聯絡人 ,現在要你給小詹打個電話 ,跟他說 ,他老婆喊他回家吃飯 。你會怎麼做 ? 當然是按姓名搜尋呀 !(假裝你有小詹電話號碼~)言歸正傳 ,那你能想到這和雜湊表有異曲同工之妙嘛 ? 雜湊表簡單說可以理解成一個對映關係
十一、雜湊演算法
業界著名的雜湊演算法也有很多,比如 MD5、SHA 等。 側重點:在實際應用中,如何用雜湊演算法解決問題? 一、概述 雜湊演算法:將任意長度的二進位制值串對映為固定長度的二進位制值串的對映規則; 雜湊值:通過原始資料對映之後得到的二進位制值串。 二、雜湊演算法的設計要求
關於一致性雜湊演算法
假設我們有 K 個機器,資料的雜湊值的範圍為 [0, MAX]。我們將整個範圍劃分為 m 個小區間(m 遠大於 K),每個機器負責 m/K 個小區間。當有新機器加入的時候,我們就將某幾個小區間的資料搬移到新機器上去。這樣,既不用全部重新計算雜湊值,搬移資料,也保持了各個機器上資料數量的均衡。 1
解讀:DENC加密演算法—雜湊演算法
2018年可以說是區塊鏈元年,隨著區塊鏈技術的落地生根,已經開始讓大眾接觸並逐步應用。有關區塊鏈的加密演算法,如今主要應用於區塊鏈技術的有以DES、AES為代表的對稱加密演算法,以RSA為代表的非對稱加密演算法,和以MD5為代表的雜湊演算法。分散式能源物聯網公司DENC,構建
【LeetCode】1. Two Sum + 雜湊演算法
傳送門:https://leetcode.com/problems/two-sum/#/description 一、題目描述 Given an array of integers, return indices of the two numbers such that they
【轉】一致性雜湊演算法
在瞭解一致性雜湊演算法之前,最好先了解一下快取中的一個應用場景,瞭解了這個應用場景之後,再來理解一致性雜湊演算法,就容易多了,也更能體現出一致性雜湊演算法的優點,那麼,我們先來描述一下這個經典的分散式快取的應用場景。 場景描述 假設,我們有三臺快取伺服器,用於快取圖片,我們為這三臺快取伺服器編號為0