java源碼Integer.bitCount算法解析,分析原理

看了一道leetcode上面的題      461 ,Hamming Distancejava

計算兩個整數有多少不一樣的位。其實很簡單,取兩個整數異或的值,而後計算出裏面二進制有多少個1就好了。代碼以下:code

public int hammingDistance(int x, int y) {
        return Integer.bitCount(x ^ y);
    }

爲何要用bitCount來統計含1的位了?爲何不直接使用循環統計每一個bit位了?leetcode

跳轉到bitCount的源碼中,以下:rem

 

public static int bitCount(int i) {
     // HD, Figure 5-2
     i = i - ((i >>> 1) & 0x55555555);
     i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
     i = (i + (i >>> 4)) & 0x0f0f0f0f;
     i = i + (i >>> 8);
     i = i + (i >>> 16);
     return i & 0x3f;
}


原來是 先 兩個兩個一組,求二進制1的個數,而且用兩位二進制存儲在原處,而後四個四個一組,求二進制位1的個數,再把它存儲以4位二進制到原處。以此類推直到計算完成。get

src store remark
00 00 這兩位沒有,那就用0存儲
01 01 這兩位只有一個1,就用1存儲
10 01 這兩位也只有一個1,也用1存儲
11 10 這兩位有兩個1,用10存儲

那麼就一對一對的數,已知 src列 求出 store列? 
列式計算:源碼

  • 設 λλ = i - x
  • 00 = 00 - 00;
  • 01 = 01 - 00;
  • 01 = 10 - 01;
  • 10 = 11 - 01;

那麼 x 又如何經過i獲得呢?it

咱們手無寸鐵,對CPU來講也只有加法和移位的手段。假如發明者列出這種算式,敏感的他一會兒 
很容易看出來: 
x=i>>>1
就這麼簡單 
那麼獲得: 
λλ = i - (i>>>1)table

那麼i不止兩位怎麼處理?若是這個是最後的兩位,那麼移位以後後面一位二進制能夠抹掉 
而前面的移位會影響後面的最高位,那麼把移出去的那一位消除: 
i>>>1 & 01; 
即爲:01010101 01010101 01010101 01010101 
λλ = i - (i>>>1 & 0x55555555)class

問題解決。 
那麼 計算了兩位的如何計算4位的二進制位呢? 
枚舉第一步計算完成的全部的狀況:循環

src target remark ref
0000 0000 = 0000 & 0011  
0001 0001 = 0001 & 0011 01 = 01 & 11
0010 0010 = 0010 & 0011 10 = 10 & 11
       
0100 0001 = 01 + 00  
0101 0010 = 01 + 01  
0110 0011 = 01 + 10  
       
1000 0010 = 10 + 00  
1001 0011 = 10 + 01  
1010 0100 = 10 + 10  

後面兩組能夠參照第一組的結果,那麼能夠推算 
四位中低兩位 bb = aabb & 0011,主要要計算與高兩位的和: 
已知能夠用1100& aabb =aa00獲得左邊的值,可是多了兩個00,那麼要計算aa + bb: 
能夠 aabb>>>2 = 00aa(bb)只看這兩位,移位多出去的被00消除,不影響後面的計算。 
即: 
λλ =( i & 0x0011) + (i>>>2 & 0x0011) 
也就是: 
λλ =( i & 0x33333333) + (i>>>2 & 0x33333333)

同理求8位裏面的兩邊4位之和: 
λλ =( i + i>>>4) & 0x0F0F0F0F

求16位的兩邊之和: 
λλ = i + (i >>> 8); 
因爲二等分是8位,而8位一共有4份。 
A B C D

(C>>>8) + D D處8位的結果最大爲 0001 0000不會進位到C。 
(B>>>8) + C C處8位的結果最大爲 0001 0000不會進位到B。 
(A>>>8) + B B處8位的結果最大爲 0001 0000不會進位到B。 
A + 0 A處最大結果爲 0000 1000

獲得 
A A+B B+C C+D 
最後是求32位所有的內容也就是求(A+B)+(C+D) 
A A+B B+C C+D 

0 0 A A+B

也就是 
λλ= i + (i >>> 16) 
A A+B A+B+C A+B+C+D  A+B+C+D最大也就32個:  0000 0000 0000 0000 0000 0000 0010 0000  0000 0000 0000 0000 0000 0000 0011 1111 = 0x3F  之因此要return i&0x3F,就是把前面抹乾淨。

相關文章
相關標籤/搜索