求二進制中1的個數(編程之美2.1)


行文脈絡

  1. 解法一——除法
  2. 解法二——移位
  3. 解法三——高效移位
  4. 解法四——查表
  5. 擴展問題——異或后轉化為該問題

 

對於一個字節(8bit)的變量,求其二進制“1”的個數。例如6(二進制0000 0110)“1”的個數為2,要求算法效率盡量高。

解法一

對於二進制數來說,除一個2,就少一位,可以判斷這個少的位來確定“1”的個數。

例如:6(0000 0110)

0000 0110 / 2 = 0000 0011     ----少的一位為0

0000 0011 / 2 = 0000 0001     ----少的一位為1

0000 0001 / 2 = 0000 0000     ----少的一位為1

操作數數已經為0,到此結束

參考代碼

int Count_1(int val)
{
    int num = 0;
    while(val)
    {
        if(val % 2 != 0)   //用取模獲得去除的一位 ++num;
        val /= 2;
    }
    return num;
}

性能:時間復雜度O(log2v),即二進制數的位數;空間復雜度O(1)

 

解法二

對於二進制數來說,除法是用移位完成。

例如:6(0000 0110)

0000 0110 >> 1 = 0000 0011     ----少的一位為0

0000 0011 >> 1 = 0000 0001     ----少的一位為1

0000 0001 >> 1 = 0000 0000     ----少的一位為1

操作數數已經為0,到此結束

參考代碼

int Count_2(int val)
{
    int num = 0;
    while(val)
    {
        if(val & 1 != 0)   //用與1與獲得移除的一位 ++num;
        val >>= 1;
    }
    return num;
}

性能:時間復雜度O(log2v),即二進制數的位數;空間復雜度O(1)

 

解法三

對於上述算法,有個問題,比如1000 0000,大把的時間用在沒用的0上,最好尋求一種直接判斷“1的個數。

通過觀察可以找到規律:對於數a, a = a & (a-1)就可以去除a的最后一個1

例如:6(0000 0110)

0000 0110 & 0000 0101 = 0000 0100     

0000 0100 & 0000 0011 = 0000 0000

操作數數已經為0,到此結束

參考代碼

int Count_3(int val)
{
    int num = 0;
    while(val)
    {
        val &= (val -1);
        ++num;
    }
    return num;
}

性能:時間復雜度O(M),即二進制中“1”的個數,空間復雜度O(1)

 

解法四

查表法,把0~255這256個數的結果全部存儲在數組中,val直接作為下標,countTable[val]即為結果。典型的用空間換時間。

參考代碼

int Count_5(int val)
{
    int countTable[] = {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};
    return countTable[val];
}

性能:時間復雜度:O(1), 空間復雜度O(N)

 

整個程序執行參考

#include<iostream>
using namespace std;

int Count_1(int val)
{
    int num = 0;
    while(val)
    {
        if(val % 2 != 0)
            ++num;
        val /= 2;
    }
    return num;
}

int Count_2(int val)
{
    int num = 0;
    while(val)
    {
        if(val & 1 != 0)
            ++num;
        val >>= 1;
    }
    return num;
}

int Count_3(int val)
{
    int num = 0;
    while(val)
    {
        val &= (val -1);
            ++num;
    }
    return num;
}
int Count_5(int val)
{
    int countTable[] = {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};
    return countTable[val];
}

int main()
{
    int a = 6, b = 255;
    cout << "Num of 1:" << Count_1(a) << endl; 
    cout << "Num of 1:" << Count_2(a) << endl; 
    cout << "Num of 1:" << Count_3(a) << endl; 
    cout << "Num of 1:" << Count_5(b) << endl; 
    cout << "Num of 1:" << Count_1(b) << endl; 
    cout << "Num of 1:" << Count_2(b) << endl; 
    cout << "Num of 1:" << Count_3(b) << endl; 
    cout << "Num of 1:" << Count_5(b) << endl; 
}
View Code

結果

 

擴展問題

1. 給定兩個正整數(二進制表示)A、B,如何快速找出A和B二進制表示中不同位數的個數。

  思路

  首先A和B進行異或操作,然后求得到的結果中1的個數(此問題)。

2. 判斷一個數是否是2的冪

bool powerof2(int n)
{
    return ((n & (n-1)) == 0);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM