編程之美之二進製數中1的個數
問題:
對於一個字節(8bit)的變量,求其二進製中1的個數,要求算法的執行效率盡可能的高。
例如把9表示成二進製是1001,有2位是1,因此如果輸入9,1的個數為2。
解法一:
可以舉一個8位二進製的例子。對於二進製操縱,我們除以一個2,原來數字就會減少一個0(向右移一位)。如果除的過程中有餘,那麼久表示當前位置有一個1。
以10100010為例:
第一次除以2時,商為1010001,餘為0
第二次除以2時,商為101000,餘為1
因此,考慮利用整形數據除法的特點,通過相除和判斷餘數的值進行分析。
- int Count(int a)
- {
- int count = 0;
- while(a)
- {
- if(a % 2 == 1)
- {
- count++;
- }
- a = a / 2;
- }
- return count;
- }
解法二:位操作
使用位操作同樣達到相除的目的。
使用與操作(&)來判斷最後一位是不是1,判斷完後向右移一位,繼續判斷。
可以把這個八位數與00000001進行與操作,如果結果為1則表示這個八位數最後一位為1,否則為0。
- int Count(int a)
- {
- int count = 0;
- while(a)
- {
- count += a & 0x01;
- a >>= 1;
- }
- return count;
- }
位操作要比除法取餘操作效率要高許多。
解法三:
作者用到一個巧妙的方法,自己與自己減1相與,(例:10100010 & 10100001 = 10100000)從而到達消去最後一位1,通過統計循環次數達到計算1的個數的目的,這個方法減少了一定的循環次數。
具體解析看看原著。
- int Count(int a)
- {
- int count = 0;
- while(a)
- {
- a = a & (a-1);
- count++;
- }
- return count;
- }
解法四:分支操作
解法三的複雜度降到O(M). 其中M為1的個數。這效率已經足夠高了。
如果還不滿足,還有一種方法。既然才是一個8位的數據(0~255),可以直接0~255的情況羅列出來,使用分支操作,得到答案。
這個方法看似很直接,但是效率可能會比其他方法要低。具體情況具體分析。如果a = 0比較一次就會得到答案,但是a = 255比較255次才得到答案
- int Count(int a)
- {
- int count = 0;
- switch(a)
- {
- case 0x0:
- count = 0;
- break;
- case 0x1:
- case 0x2:
- case 0x4:
- case 0x8:
- case 0x10:
- case 0x20:
- case 0x40:
- case 0x80:
- count = 1;
- break;
- case 0x3:
- case 0x6:
- case 0xc:
- case 0x18:
- case 0x30:
- case 0x60:
- case 0xc0:
- count = 2;
- break;
- //.....
- }
- return count;
- }
解法五:查表法
直接把0~255相應1的個數直接存在數組中,采取以空間換取時間。
- int CountTable[256] =
- {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
- 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
- 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
- };
- int Count(int a)
- {
- return CountTable[a];
- }
最後更新:2017-04-03 12:54:47