<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Integer中的奇妙位運(yùn)算

          共 4386字,需瀏覽 9分鐘

           ·

          2020-12-08 18:23

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          ? 作者?|??南風(fēng)知我不易

          來(lái)源 |? urlify.cn/zaIv22

          66套java從入門到精通實(shí)戰(zhàn)課程分享

          Integer中的奇妙位運(yùn)算

          參考資料

          https://segmentfault.com/a/1190000015763941

          highestOneBit(int i)

          函數(shù)的作用是獲得傳入?yún)?shù)的最高位的1,對(duì)于正數(shù)來(lái)說(shuō)返回值為小于i的最大二次冪,對(duì)于負(fù)數(shù)來(lái)說(shuō)永遠(yuǎn)是負(fù)數(shù)的最大值即-2^31

          例如:7=0000 0111(省略前24位0)那么函數(shù)的返回值為 0000 0100=4

          暴力法

          通常來(lái)說(shuō)最直觀的做法就是暴力法,我一個(gè)一個(gè)數(shù)不就好了

          //一位一位取就是了
          public?int?heigestOneBit(int?i){
          ????int?res=1;
          ????if?(i<0)return?Integer.MIN_VALUE;
          ????while(i!=0){
          ????????if?(i!=1){
          ????????????res*=2;
          ????????}
          ????????i/=2;
          ????}
          ????return?res;
          }

          位運(yùn)算

          看看JDK如何利用更加高效的位操作實(shí)現(xiàn)這一個(gè)函數(shù)

          public?static?int?highestOneBit(int?i)?{
          ????//?HD,?Figure?3-1
          ????i?|=?(i?>>??1);
          ????i?|=?(i?>>??2);
          ????i?|=?(i?>>??4);
          ????i?|=?(i?>>??8);
          ????i?|=?(i?>>?16);
          ????return?i?-?(i?>>>?1);
          }

          為什么JDK一通位操作就把最高位取出來(lái)了呢?非常的巧妙啊,舉例說(shuō)明,看以下就知道了

          //以下以數(shù)字為例,其中x表示0或者1不影響結(jié)果,1-最高位的1
          i???????????????0000?001x?xxxx?xxxx?xxxx?xxxx?xxxx?xxxx
          i>>1??0000?0001?xxxx?xxxx?xxxx?xxxx?xxxx?xxxx
          i|=(i>>1)?0000?0011?xxxx?xxxx?xxxx?xxxx?xxxx?xxxx

          i??0000?0011?xxxx?xxxx?xxxx?xxxx?xxxx?xxxx
          i>>2??0000?0000?11xx?xxxx?xxxx?xxxx?xxxx?xxxx
          i|=(i>>2)?0000?0011?11xx?xxxx?xxxx?xxxx?xxxx?xxxx

          i??0000?0011?11xx?xxxx?xxxx?xxxx?xxxx?xxxx
          i>>4??0000?0000?0011?11xx?xxxx?xxxx?xxxx?xxxx
          i|=(i>>4)?0000?0011?1111?11xx?xxxx?xxxx?xxxx?xxxx

          i??0000?0011?1111?11xx?xxxx?xxxx?xxxx?xxxx
          i>>8??0000?0000?0000?0011?1111?11xx?xxxx?xxxx
          i|=(i>>8)?0000?0011?1111?1111?1111?11xx?xxxx?xxxx

          i??0000?0011?1111?1111?1111?11xx?xxxx?xxxx
          i>>16??0000?0000?0000?0000?0000?0011?1111?1111
          i|=(i>>16)?0000?0011?1111?1111?1111?1111?1111?1111

          i??0000?0011?1111?1111?1111?1111?1111?1111
          i>>>1??0000?0001?1111?1111?1111?1111?1111?1111
          i-(i>>>1)?0000?0010?0000?0000?0000?0000?0000?0000

          看完上面的簡(jiǎn)單分析應(yīng)該就知道JDK如何實(shí)現(xiàn)的了,簡(jiǎn)單來(lái)說(shuō)就是把第一個(gè)1不斷往后移動(dòng),使得從第一個(gè)1之后的所有比特位都為1,此時(shí)減去右移一位的值,也就是減去后面所有的1代表的值,此時(shí)自然只剩下第一個(gè)1了,可以說(shuō)非常的巧妙了

          bitCount(int i)

          該方法的作用是統(tǒng)計(jì)一個(gè)整數(shù)的二進(jìn)制表示形式中1的個(gè)數(shù),沒(méi)記錯(cuò)的話這其實(shí)也是leetcode中的一道題

          首先還是我們自己來(lái)思考一下如何實(shí)現(xiàn):

          暴力法

          一個(gè)bit一個(gè)bit計(jì)數(shù)

          public?static?int?bitCount(int?i){
          ????//暴力法
          ????int?count=0;
          ????while(i!=0){
          ????????if?((i&1)==1){
          ????????????count++;
          ????????}
          ????????i=i>>>1;
          ????}
          ????return?count;
          }

          位運(yùn)算優(yōu)化一下

          試想對(duì)于二進(jìn)制 100,1的個(gè)數(shù)為1,按照暴力法需要3次才能統(tǒng)計(jì)出來(lái),怎么樣一次統(tǒng)計(jì)出來(lái)呢,也就是怎么一次就把100變成0呢?

          對(duì)于1xxx這樣的數(shù)字,x代表0,以100為例,100-1=011,而100&011恰好為0,能做多少次這樣的運(yùn)算,它就有多少位1,代碼如下

          public?static?int?bitCount(int?i){
          ????//位運(yùn)算優(yōu)化
          ????int?count=0;
          ????while(i!=0){
          ????????i=i&(i-1);
          ????????count++;
          ????}
          ????return?count;
          }

          到這里,有多少位的1,就統(tǒng)計(jì)多少次,貌似看起來(lái)已經(jīng)還算不錯(cuò)了

          JDK的位運(yùn)算

          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;
          }

          Superise Mother Fxxk!這是在干什么?首先解釋一下總體的思想

          //要統(tǒng)計(jì)如下二進(jìn)制的:1001 1010 1010 1010?的1的位數(shù)
          //JDK是這樣做的
          先每?jī)蓚€(gè)bit統(tǒng)計(jì)有多少個(gè)1,然后就保存在二進(jìn)制的本地
          10?01?10?10?10?10?10?10
          01?01?01?01?01?01?01?01
          然后再統(tǒng)計(jì)連續(xù)四個(gè)bit有多少個(gè)1,然后保存在本地
          0010?0010?0010?0010
          再統(tǒng)計(jì)8個(gè)bit有多少個(gè)1,保存在本地
          0000?0100?0000?0100
          然后再統(tǒng)計(jì)每16個(gè)比特有多少個(gè)1,保存再本地
          0000?0000?0000?1000?==8總共8個(gè)1

          有了整體的算法思想,來(lái)看看這幾個(gè)奇怪的數(shù)字0x555555550x333333330x0f0f0f0f

          他們對(duì)應(yīng)的二進(jìn)制如下:

          0x55555555???01010101010101010101010101010101
          0x33333333???00110011001100110011001100110011
          0x0f0f0f0f???00001111000011110000111100001111

          針對(duì)0x55555555來(lái)看看效果,怎么把兩個(gè)相鄰bit位中的1存儲(chǔ)下來(lái),

          //以12345為例
          12345????0000?0000?0000?0000?0011?0000?0011?1001
          0x55555555???0101?0101?0101?0101?0101?0101?0101?0101
          12345&
          0x55555555???0000?0000?0000?0000?0001?0000?0001?0001
          //可以看到相當(dāng)于把兩個(gè)相鄰的比特位的后一位的1全部取出來(lái)了
          12345>>>1???0000?0000?0000?0000?0001?1000?0001?1100
          0x55555555???0101?0101?0101?0101?0101?0101?0101?0101
          12345>>>1
          &0x55555555???0000?0000?0000?0000?0001?0000?0001?0100
          //可以看到相當(dāng)于把兩個(gè)相鄰的比特位的前一位的1全部取出來(lái)了
          12345????00?00?00?00?00?00?00?00?00?11?00?00?00?11?10?01
          last?1????00?00?00?00?00?00?00?00?00?01?00?00?00?01?00?01
          first?1????00?00?00?00?00?00?00?00?00?01?00?00?00?01?01?00
          last1+fisrt1??00?00?00?00?00?00?00?00?00?10?00?00?00?10?01?01
          //可以看到兩位中的1的數(shù)量已經(jīng)用兩個(gè)bit來(lái)保存了

          算法實(shí)現(xiàn)如下:

          public?static?int?bitCount(int?i)?{
          ????i?=?(i?&?0x55555555)?+?((i?>>>?1)?&?0x55555555);
          ????i?=?(i?&?0x33333333)?+?((i?>>>?2)?&?0x33333333);
          ????i?=?(i?&?0x0f0f0f0f)?+?((i?>>>?4)?&?0x0f0f0f0f);
          ????i?=?(i?&?0x00ff00ff)?+?((i?>>>?8)?&?0x00ff00ff);
          ????i?=?(i?&?0x0000ffff)?+?((i?>>>?16)?&?0x0000ffff);
          ????return?i;
          }

          JDK再做點(diǎn)優(yōu)化即可

          • 第一步,對(duì)于 11 這兩個(gè)比特位來(lái)說(shuō),用 01 + 01 的方式可以得到 10 也可以用 11 - 01 的方式,所以可以少做一次位運(yùn)算

          • 第三步,統(tǒng)計(jì)兩個(gè) 4個(gè)連續(xù)bit 中1的個(gè)數(shù),例如 0011 0011 -> 0000 1100 ,而8個(gè)bit最多就8個(gè)1,用4個(gè)bit就可以表示了,所以可以先加,0011 1100,再消除,0000 1100,第四步第五步同理,前面的留著不管,最后返回的時(shí)候把前面的bit置0

          • return i & 0x3f,32位的int,最多就32個(gè)1,所以取后六位即可表示所有的可能

          上述兩者的使用

          上面兩個(gè)方法均在HashMap(JDK7實(shí)現(xiàn))中的roundroundUpToPowerOf2方法中被調(diào)用,HashMap的分析詳見(jiàn)https://www.cnblogs.com/danzZ/p/14075147.html,還是非常有意思的



          粉絲福利:實(shí)戰(zhàn)springboot+CAS單點(diǎn)登錄系統(tǒng)視頻教程免費(fèi)領(lǐng)取

          ???

          ?長(zhǎng)按上方微信二維碼?2 秒
          即可獲取資料



          感謝點(diǎn)贊支持下哈?

          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产高清无码黄片 | 黄色大全在线免费观看 | 偷拍视频综合网 | 99久久精品无码一区二区 | 情趣内裤操逼网站在线 |