程式設計之美讀書筆記2 1 求二進位制數中1的個數

2021-10-22 17:01:36 字數 3196 閱讀 2802

解法一:

可以舉乙個8位二進位制的例子。對於二進位制操縱,我們除以乙個2,原來數字就會減少乙個0(向右移一位)。如果除的過程中有餘,那麼久表示當前位置有乙個1。

以10100010為例:

第一次除以2時,商為1010001,余為0

第二次除以2時,商為101000,余為1

因此,考慮利用整形資料除法的特點,通過相除和判斷餘數的值進行分析。

int count(int a)

a = a / 2;

}return count;

}

解法二:位操作

使用位操作同樣達到相除的目的。

使用與操作(&)來判斷最後一位是不是1,判斷完後向右移一位,繼續判斷。

可以把這個八位數與00000001進行與操作,如果結果為1則表示這個八位數最後一位為1,否則為0

int count(int a)

return count;

}

解法三:

作者用到乙個巧妙的方法,自己與自己減1相與,(例:10100010 & 10100001 = 10100000)從而到達消去最後一位1,通過統計迴圈次數達到計算1的個數的目的,這個方法減少了一定的迴圈次數。

具體解析看看原著。

int count(int a)

return count;

}

解法四:分支操作

解法三的複雜度降到o(m). 其中m為1的個數。這效率已經足夠高了。

如果還不滿足,還有一種方法。既然才是乙個8位的資料(0~255),可以直接0~255的情況羅列出來,使用分支操作,得到答案。

這個方法看似很直接,但是效率可能會比其他方法要低。具體情況具體分析。如果a = 0比較一次就會得到答案,但是a = 255比較255次才得到答案

int count(int a)

return count;

}

解法五:查表法

直接把0~255相應1的個數直接存在陣列中,採取以空間換取時間。時間複雜度為1。

int counttable[256] =     ; 

int count(int a)

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

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

首先構造乙個包含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)00000000000000000000000010101011

int bitcount7(unsigned int n)

; return table[n &0xff] +

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

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

table[(n >>24) &0xff] ;

}

int bitcount4(unsigned int n) 

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

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

程式設計之美2 1 求二進位制中1的個數

最近一段的時間,一直在看程式設計之美之類的演算法書籍,剛開始看程式設計之美,感覺到難度太大,有時候也不願意去翻動這本書,不過,經過一段時間的修煉,我也徹底的喜歡上這本書了,書中的演算法涉及到很多方面,樹,鍊錶,位運算,陣列,hash表應用等等。由於最近事情也忙得差不多了,我重新寫了一遍程式設計之美中...

求二進位制中1的個數(程式設計之美2 1)

行文脈絡 解法一 除法 解法二 移位 解法三 高效移位 解法四 查表 擴充套件問題 異或後轉化為該問題 對於乙個位元組 8bit 的變數,求其二進位制 1 的個數。例如6 二進位制0000 0110 1 的個數為2,要求演算法效率盡量高。解法一 對於二進位制數來說,除乙個2,就少一位,可以判斷這個少...

程式設計之美2 1 求二進位制樹中1的個數

問題 對乙個4位元組的無符號整形變數,求其二進位制表示中 1 的個數,要求演算法的執行效率盡可能高。解法一 位遍曆法 使用位操作,移位後來判斷是否有1存在,利用v 0x01和v 1。解法二 1遍曆法 在每次判斷中只與1的個數進行判斷,利用v v 1。解法三 二分累加法 依次連續兩位相加,連續四位相加...