日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

编程之美求二进制数中1的个数扩展题

發布時間:2025/3/21 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编程之美求二进制数中1的个数扩展题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://s.sousb.com/?p=253

編程之美2.1節中的擴展題第1題:如果變量是32位的Dword,則如何統計該二進制數中1的個數。

對于該題,原本的想法還是想采用書中解法三,也就是用統計1中個數的算法v&(v-1),該算法時間復雜度為該32二進制數中“1”的個數。后來,參見了書中鏈接里的解法,該解法甚妙,復雜度只有若干個位運算,與“1”的數目無關。由于下面這段程序寫的比較難懂,所以在這里解釋一下他的解法。

解法一:

view plaincopy to clipboardprint?
  • int?Count(unsigned?x)??
  • {??
  • ???x?=?x?-?((x?>>?1)?&?0x55555555);??//?1??
  • ???x?=?(x?&?0x33333333)?+?((x?>>?2)?&?0x33333333);???//?2??
  • ???x?=?(x?+?(x?>>?4))?&?0x0F0F0F0F;????//3??
  • ???x?=?x?+?(x?>>?8);???//4??
  • ???x?=?x?+?(x?>>?16);???//5??
  • ???return?x?&?0x0000003F;??//?6??
  • }??
  • 我們以0000 0000 0000 0000 0000 0000 1011 0101為例:

    第一行中,x>>1是右移一位,(x>>1) 為 0000 0000 0000 0000 0000 0000 0101 1010,該結果與0101 0101 0101 0101 0101 0101 0101 0101相與,等于 0000 0000 0000 0000 0000 0000 0101 0000,實際上,((x >> 1) & 0×55555555) 該步是想得到原數據x的偶數位的數據。(代碼是先右移,再得奇數位,這個等價于:先得偶數位,再右移)然后,x-((x >> 1) & 0×55555555) 則是 用原數據減去原數據的偶數位。結果是 0000 0000 0000 0000 0000 0000 0110 0101,其實,之所有要相減就是為了得到第一位與第二位1的個數的和,第三位與第四位1的個數的和,第五位與第六位1的個數的和,以此類推。那么,為什么要用相減的方法來得到相鄰兩位的和呢?原理是:相鄰兩位1的個數的和是:A-A/2 。原數據是A,右移相當于除2。比如,如果原數據是1(01),那么一半就是0,相減后就是1,所以有1個“1”。如果原數據是3(11),那么一半就是1,相減后就是2,所有總共有2個“1”。這樣,經過第一行的運算,我們得到每兩個相鄰位的“1”的總和。

    第二行,類似的,是求將原數據第一位第二位的“1“的個數的和 與 第三位第四位的“1”的個數的和 相加。這樣,第二行執行后,我們可以得到每四位的“1”的個數的和

    第三行,可以得到每八位的“1”的個數的和

    第四行,可以得到每16位“1”的個數的和

    第五行,可以得到32位數中所有1的個數的和。

    第六行,由于32位的數據,1的個數最大也就32個,不可能超過2的6位方,所以只要取最后6位數據就是所有數據1的個數的和了。

    這里用的是二分法,兩兩一組相加,之后四個四個一組相加,接著八個八個,最后就得到各位之和了。

    解法二:

    view plaincopy to clipboardprint?
  • int?Count(unsigned?x)??
  • {??
  • ???unsigned?n;??????
  • ??
  • ???n?=?(x?>>?1)?&?033333333333;???//?1??
  • ???x?=?x?-?n;??//?2??
  • ???n?=?(n?>>?1)?&?033333333333;??//?3??
  • ???x?=?x?-?n;???//?4??
  • ???x?=?(x?+?(x?>>?3))?&?030707070707;??//5??
  • ???x?=?modu(x,?63);???//?6??
  • ???return?x;??//7??
  • }??
  • 這個解法更妙。需要注意的是,033333333333和033333333333都是指 八進制的數。第一行第二行連起來看,這與解法一很類似,目的是為了得到第一位與第二位的“1”的個數和。注意,第31、32位中1的個數和在這一步中被統計好了。

    第一行和第三行、第四行連起來看,目的是為了得到第一位與第三位的“1”的個數的和。然后,再與上步的結果加起來,就得到第一位、第二位、第三位的“1”的個數的和。所以,從第一行到第四行就是為了得到 每三位一組的“1”的個數的和。原理是:

    相鄰三位的結果是:A-A/2-A/4. 算法中有兩次向移。比如,第一位第二位第三位是011, 則第一次移位后為01,相減后為10,再移位后為0,相減還是10,所以有2個“1”。再比如,第一位第二位第三位是101,則第一次移位后為10,相減后為011,再移位后為1,相減后是010,所以有2個“1”。第五行是求相鄰六位的1的個數第六行,比較難懂。在第五行執行完后,我們得到了七組數據,第32、31位為一組,第30-25為一組,……第6-第1為一組。所以可以寫成:x_0 + x_1 * 64 + x_2 * 64 * 64 + x_3 * 64 * 64* 64+ x_4 * 64 * 64* 64* 64+ x_5 * 64 * 64* 64* 64* 64+ x_6 * 64 * 64* 64* 64* 64* 64,這個數除以63的余數 肯定 與 x_0 +……+x_6 相等(因為32位的數據最多也就32個1)簡短解釋:首先是將二進制各位三個一組,求出每組中1的個數,然后相鄰兩組歸并,得到六個一組的1的個數,最后很巧妙的用除63取余得到了結果。

    這個程序只需要十條左右指令,而且不訪存,速度很快。

    總結

    以上是生活随笔為你收集整理的编程之美求二进制数中1的个数扩展题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。