探索Integer番外篇之Integer.bitCount(int i)

1. 前言

錢不是真正的花掉了,而是換了一種方式陪在你身邊

bitCount:統(tǒng)計int類型數(shù)值的二進制中1的個數(shù)。
在各種版本的面試寶典中,這個題目應(yīng)該是非常常見的了。比如《劍指offer》面試題10:二進制中1的個數(shù),《編程之美》2.1 求二進制數(shù)中1的個數(shù),實現(xiàn)方法非常之多,各有千秋。
我們來看看jdk中是如何實現(xiàn)的。

2. 源碼


相比較其他的解法,這個是非常新穎的方式,不愧于大師之筆。

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

解析過程:
輸入 i,
i = b_0*2^0 + b_1*2^1 + b_2*2^2 + ... + b_{30}*2^{30} + b_{31}*2^{31} \tag{2.1},
其中 b_0,b_1,b_2...b_{31}
要么為0,要么為1,則,統(tǒng)計二進制1的個數(shù),實則求
b_0+b_1+b_2+...+b_{31}
第1步:i = i - ((i >>> 1) & 0x55555555);
i >>> 1的結(jié)果
b_1*2^0 + b_2*2^1 + ... + b_{31}*2^{30}\tag{2.2}
而0x55555555中 5 表示 0101,與運算就是取奇數(shù)位(取第0位,第2位,第4位...),則
(i>>>1) & 0x55555555的結(jié)果為
b_1*2^0 + b_3*2^2 + b_5*2^4 +...+ b_{31}*2^{30} \tag{2.3}
i = i - ((i >>> 1) & 0x55555555)的結(jié)果為(2.2+2.3)
\begin{eqnarray*} i &=& (b_0-b_1)*2^0 + b_1*2^1 + (b_2-b_3)*2^2 + ... + (b_{30}-b_{31})*2^{30} + b_{31}*2^{31} \\&=&(b_0+b_1)*2^0 + (b_2+b_3)*2^2+...+(b_{30}+b_{31})*2^{30} \tag{2.4} \end{eqnarray*}
第2步:i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
0x33333333中 表示 0011,與運算就是每四位取前兩位
i & 0x33333333的結(jié)果為
(b_0+b_1) * 2^0 + (b_4+b_5) * 2^4 + (b_8+b_9) * 2^8 +...+(b_{28}+b_{29})*2^{28} \tag{2.5}
(i>>>2) & 0x33333333的結(jié)果為
(b_2+b_3) * 2^0 + (b_6+b_7)*2^4 + (b_10+b_11)*2^{8} +...+(b_{30}+b_{31})*2^{28} \tag{2.6}
i = (i & 0x33333333) + ((i>>>2) & 0x33333333)的結(jié)果為(2.5 + 2.6)
\begin{eqnarray*} i &=&(b_0+b_1+b_2+b_3)*2^0 + (b_4+b_5+b_6+b_7)*2^4+...+(b_{28}+b_{29}+b_{30}+b_{31})*2^{28} \tag{2.7} \end{eqnarray*}
第3步:i = (i + (i >>> 4)) & 0x0f0f0f0f;
i + (i>>>4)的結(jié)果為
\begin{eqnarray*} (b_0+b_1+b_2+b_3+b_4+b_5+b_6+b_7)*2^0 + (b_4+b_5+b_6+b_7+b_8+b_9+b_{10}+b_{11})*2^4 +\\...+(b_{24}+b_{25}+b_{26}+b_{27}+b_{28}+b_{29}+b_{30}+b_{31})*2^{24}+(b_{28}+b_{29}+b_{30}+b_{31})*2^{28} \end{eqnarray*}
而0x0f0f0f0f中,與運算表示每8位取前四位,
則i = (i + (i>>>4)) & 0x0f0f0f0f的結(jié)果為
\begin{eqnarray*} i=(b_0+b_1+b_2+b_3+b_4+b_5+b_6+b_7)*2^0 + (b_8+b_9+b_{10}+b_{11} +b_{12}+b_{13}+b_{14}+b_{15})*2^8 +\\...+(b_{24}+b_{25}+b_{26}+b_{27}+b_{28}+b_{29}+b_{30}+b_{31})*2^{24} \end{eqnarray*}
第4步:i = i + (i >>> 8);
i = i + (i>>>8)的結(jié)果為
\begin{eqnarray*} i=&(&b_0+b_1+b_2+...+b_{14}+b_{15})*2^0 +(b_8+b_9+b_{10}+...+b_{22}+b_{23})*2^8+ \\&(&b_{24}+b_{25}+b_{26}+...+b_{30}+b_{31})*2^{16} +(b_{24}+b_{25}+b_{26}+...+b_{30}+b_{31})*2^{24} \end{eqnarray*}
第5步:i = i + (i >>> 16);
i = i + (i>>>16)的結(jié)果為
\begin{eqnarray*} i=&(&b_0+b_1+b_2+...+b_{30}+b_{31})*2^0 +(b_8+b_9+b_{10}+...+b_{30}+b_{31})*2^8+ \\&(&b_{24}+b_{25}+b_{26}+...+b_{30}+b_{31})*2^{16} +(b_{24}+b_{25}+b_{26}+...+b_{30}+b_{31})*2^{24} \end{eqnarray*}
第5步:i & 0x3f
0x3f表示只取二進制前6位
結(jié)果為:
\begin{eqnarray*} i&=&(b_0+b_1+b_2+...+b_{30}+b_{31})*2^0 \\&=&b_0+b_1+b_2+...+b_{30}+b_{31} \end{eqnarray*}
即為二進制1的個數(shù)

3.后言

6步法求二進制1的個數(shù),你學(xué)會了嗎?


其他

本人也是在慢慢學(xué)習(xí)中,如有錯誤還請原諒、敬請指出,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,569評論 0 13
  • 在C語言中,五種基本數(shù)據(jù)類型存儲空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 4,061評論 0 2
  • Integer類為java基本類型int的包裝類,除了前面提到的Byte類,Short類中的大部分方法,Integ...
    Kinsanity閱讀 958評論 0 2
  • 放假前已作了假期規(guī)劃,帶回好幾本書,立志暑假要在家看書,不能讓時間虛度。 誰知到家沒有歇腳的余地,完成一件...
    寧_5687閱讀 344評論 0 2
  • 李晨是我的同學(xué)。每次他在上課的時候睡覺,我就坐在他旁邊,寫關(guān)于他的故事。下課了,他醒了,我也就寫完了。 她脫下上衣...
    曉平閱讀 553評論 0 2

友情鏈接更多精彩內(nèi)容