演算法 求二進位制數中1的個數

2021-07-10 21:01:33 字數 3315 閱讀 5874

任意給定乙個32位無符號整數n,求n的二進位制表示中1的個數,比如n = 5(0101)時,返回2,n = 15(1111)時,返回4

這也是一道比較經典的題目了,相信不少人面試的時候可能遇到過這道題吧,下面介紹了幾種方法來實現這道題,相信很多人可能見過下面的演算法,但我相信很少有人見到本文中所有的演算法。如果您上頭上有更好的演算法,或者本文沒有提到的演算法,請不要吝惜您的**,分享的時候,也是學習和交流的時候。

我總是習慣叫普通法,因為我實在找不到乙個合適的名字來描述它,其實就是最簡單的方法,有點程式基礎的人都能想得到,那就是移位+計數,很簡單,不多說了,直接上**,這種方法的運算次數與輸入n最高位1的位置有關,最多迴圈32次。

按 ctrl+c 複製**

按 ctrl+c 複製**

乙個更精簡的版本如下

int bitcount1(unsigned int

n)

這種方法速度比較快,其運算次數與輸入n的大小無關,只與n中1的個數有關。如果n的二進位制表示中有k個1,那麼這個方法只需要迴圈k次即可。其原理是不斷清除n的二進位制表示中最右邊的1,同時累加計數器,直至n為0,**如下

int bitcount2(unsigned int

n)

return

c ;}

為什麼n &= (n – 1)能清除最右邊的1呢?因為從二進位制的角度講,n相當於在n - 1的最低位加上1。舉個例子,8(1000)= 7(0111)+ 1(0001),所以8 & 7 = (1000)&(0111)= 0(0000),清除了8最右邊的1(其實就是最高位的1,因為8的二進位制中只有乙個1)。再比如7(0111)= 6(0110)+ 1(0001),所以7 & 6 = (0111)&(0110)= 6(0110),清除了7的二進位制表示中最右邊的1(也就是最低位的1)。

由於表示在程式執行時動態建立的,所以速度上肯定會慢一些,把這個版本放在這裡,有兩個原因

1. 介紹填表的方法,因為這個方法的確很巧妙。

2. 型別轉換,這裡不能使用傳統的強制轉換,而是先取位址再轉換成對應的指標型別。也是常用的型別轉換方法。

int bitcount3(unsigned int

n) ;

//初始化表

for (int i =0; i <256; i++)

unsigned

int c =0

;

//查表

unsigned char* p = (unsigned char*) &n ;

c = bitssettable256[p[0]] +bitssettable256[p[

1]] +bitssettable256[p[

2]] +bitssettable256[p[

3]];

return

c ;

}

先說一下填表的原理,根據奇偶性來分析,對於任意乙個正整數n

1.如果它是偶數,那麼n的二進位制中1的個數與n/2中1的個數是相同的,比如4和2的二進位制中都有乙個1,6和3的二進位制中都有兩個1。為啥?因為n是由n/2左移一位而來,而移位並不會增加1的個數。

2.如果n是奇數,那麼n的二進位制中1的個數是n/2中1的個數+1,比如7的二進位制中有三個1,7/2 = 3的二進位制中有兩個1。為啥?因為當n是奇數時,n相當於n/2左移一位再加1。

再說一下查表的原理

對於任意乙個32位無符號整數,將其分割為4部分,每部分8bit,對於這四個部分分別求出1的個數,再累加起來即可。而8bit對應2^8 = 256種01組合方式,這也是為什麼表的大小為256的原因。

注意型別轉換的時候,先取到n的位址,然後轉換為unsigned char*,這樣乙個unsigned int(4 bytes)對應四個unsigned char(1 bytes),分別取出來計算即可。舉個例子吧,以87654321(十六進製制)為例,先寫成二進位制形式-8bit一組,共四組,以不同顏色區分,這四組中1的個數分別為4,4,3,2,所以一共是13個1,如下面所示。

10000111

01100101

01000011

00100001 = 4 + 4 + 3 + 2 = 13

原理和8-bit表相同,詳見8-bit表的解釋

int bitcount4(unsigned int

n) ;

unsigned

int count =0

;

while

(n)

return

count ;

}

首先構造乙個包含256個元素的表table,table[i]即i中1的個數,這裡的i是[0-255]之間任意乙個值。然後對於任意乙個32bit無符號整數n,我們將其拆分成四個8bit,然後分別求出每個8bit中1的個數,再累加求和即可,這裡用移位的方法,每次右移8位,並與0xff相與,取得最低位的8bit,累加後繼續移位,如此往復,直到n為0。所以對於任意乙個32位整數,需要查表4次。以十進位制數2882400018為例,其對應的二進位制數為10101011110011011110111100010010,對應的四次查表過程如下:紅色表示當前8bit,綠色表示右移後高位補零。

第一次(n & 0xff)             10101011110011011110111100010010

第二次((n >> 8) & 0xff)  00000000101010111100110111101111

第三次((n >> 16) & 0xff)00000000000000001010101111001101

第四次((n >> 24) & 0xff)000000000000000000000000

10101011

int bitcount7(unsigned int

n);

return table[n &0xff] +table[(n >>8) &0xff] +table[(n >>16) &0xff] +table[(n >>24) &0xff

] ;}

當然也可以搞乙個16bit的表,或者更極端一點32bit的表,速度將會更快。

網上都這麼叫,我也這麼叫吧,不過話說回來,的確有平行的意味在裡面,先看**,稍後解釋

int bitcount4(unsigned int

n)

速度不一定最快,但是想法絕對巧妙。 說一下其中奧妙,其實很簡單,先將n寫成二進位制形式,然後相鄰位相加,重複這個過程,直到只剩下一位。

以217(11011001)為例,有圖有真相,下面的圖足以說明一切了。217的二進位制表示中有5個1

演算法 求二進位制數中1的個數

任意給定乙個32位無符號整數n,求n的二進位制表示中1的個數,比如n 5 0101 時,返回2,n 15 1111 時,返回4 這也是一道比較經典的題目了,相信不少人面試的時候可能遇到過這道題吧,下面介紹了幾種方法來實現這道題,相信很多人可能見過下面的演算法,但我相信很少有人見到本文中所有的演算法。...

演算法 求二進位制數中1的個數

任意給定乙個32位無符號整數n,求n的二進位制表示中1的個數,比如n 5 0101 時,返回2,n 15 1111 時,返回4 這也是一道比較經典的題目了,相信不少人面試的時候可能遇到過這道題 方式一 移位 計數 int bitcount unsigned int n return c int bi...

求二進位制數中1的個數

解法一 可以舉乙個八位的二進位制例子來進行分析。對於二進位制操作,我們知道,除以乙個2,原來的數字將會減少乙個0。如果除的過程中有餘,那麼就表示當前位置有乙個1。以10 100 010為例 第一次除以2時,商為1 010 001,余為0。第二次除以2時,商為101 000,余為1。因此,可以考慮利用...