求二進制數中1的個數

  <<編程之美>>中有這麼個題目:對於一個字節的無符號整形變量,求其二進制表達形式中「1」的個數。算法

  基礎算法:展轉相除法編程

  展轉相除法是十進制採用的算法,該算法以下:spa

int count_one_cnt(int value)
{
    int cnt = 0;
    while (value)
    {
        if (value % 2 == 1)
        {
            cnt += 1;
        }
        value /= 2;
    }
    return cnt;
}

  上述算法的時間複雜度O(logV)(V是value比特數),上述算法的操做對象的級別是「數」級別的,題目的要求是「位」級別的,所以若是可以經過位運行完成題目要求功能,將會更加高效:1)除法採用右移實現;2)經過與1位與運算判斷是否有1的存在。code

int count_one_cnt(int value)
{
    int cnt = 0;
    while (value)
    {
        cnt += value & 1;
        value >>= 1;
    }
    return cnt;
}

  位與法:對象

  上面的兩個算法時間複雜度均依賴於欲求的數據類型在存儲空間中佔有的比特數,位與法算法複雜度則僅與待求數據中1的個數相關。首先,觀察某個數a與a-1:在二進制下,a-1在最右端加上1就等於a,a與a-1進行位與運算則會消除最右邊的1,能夠從如下角度理解;blog

  1)a與a-1僅差一個1,而這個1是從a-1最低端加上便等於aip

  2)假設a最低端出現的位置pos,pos後面均是0,所以與b位與運算,pos位置後面均是0字符串

  3)a-1的對應pos位置,必定是0。假設a-1在pos位置等於1,a-1後面必然均是0,不然a-1將會大於a,但根據1)a等於a-1處最低端位加1,而a-1從pos位置開始均是0,在a-1最低端位加1獲得的a,在pos位置到最低端必定有一個1,與2)矛盾。get

  雖然理解起來有些繞彎,可是代碼倒是很是簡潔的:it

int count_one_cnt(int value)
{
    int cnt = 0;
    while (value)
    {
        value &= value-1;
        cnt += 1;
    }
    return cnt;
}

  位圖法:

  <<編程之美>>提到了這種方法:8bit的無符號整數的範圍是[0, 255),所以直接將256個數還有的1位數作出表的形式,以時間換空間~實現方法在此省略。

  Hamming weight方法:

  Hamming weight:是指在給定的字符串中,全部不等於0的字符的個數,在一串二進制的字符串中,等於該二進制中1的個數。Hamming weight方法的一種快速實現,採用了「隔位相加」的方法:相鄰位相加,並存在與當前位置中。算法過程以下(來源與維基百科):

能夠從下圖快速理解算法的執行過程:

  

實現方法在此不一一列出,有興趣能夠參考維基百科中給出了三種實現方法~

相關文章
相關標籤/搜索