hashMap高低位異或原理


  1. 散列函數
    將整數散列最常用的方法就是除留余數法。為了均勻地散列鍵的散列值,通常都會把數組的大小取素數(HashTable 的初始大小就是 11),因為素數的因子少,余數相等的概率小,沖突的幾率就小。

HashMap 的容量始終是 2 的次冪,這是一個合數,之所以這樣設計,是為了將取模運算轉為位運算,提高性能。這個等式h % length = h & (length-1)成立的原因如下:

2^1 = 10          2^1 -1 = 01 
2^2 = 100         2^2 -1 = 011 
2^3 = 1000        2^3 -1 = 0111
2^n = 1(n個零)     2^n -1 = 0(n個1) 

右邊是 2^n 的二進制特點,左邊是 2^n-1 的特點,可以發現當 length = 2^n 時,h & (length-1) 的結果正好位於 0 到 length-1 之間,就相當於取模運算。

轉為位運算后,length-1 就相當於一個低位掩碼,在按位與時,它會把原散列值的高位置0,這就導致散列值只在掩碼的小范圍內變化,顯然增大了沖突幾率。為了減少沖突,HashMap 在設計散列算法時,使用高低位異或,變相的讓鍵的高位也參與了運算,代碼如下:

static final int hash(Object key) { // JDK8
  int h;
  // h = key.hashCode()  1. 取hashCode值
  // h ^ (h >>> 16)      2. 高16位與低16位異或,變相保留高位的比特位
  return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
// JDK7 的源碼,JDK8 沒有這個方法,但原理一樣
static int indexFor(int h, int length) {
   return h & (length-1); // 3. 取模運算
}

高位的移位異或,既能保證有效的利用鍵的高低位信息,又能減少系統開銷,這樣設計是對速度、效率和質量之間的權衡。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM