zoukankan      html  css  js  c++  java
  • 判断32位无符号整数二进制中1的个数

    1、比较简单和容易理解的方法就是逐位比较法:

    #include <iostream>  
    using namespace std;

    int findone(unsigned int n)
    {
    for(int i=0;n>0;n>>=1)
    i+=(n&1);
    return i;
    }

    int main(){
    int n;
    cin>>n;
    cout<<findone(n)<<endl;
    return 0;
    }

    这种方法的缺点是比较费时,时间长度取决于n的位数,时间复杂度O(n)。假如上千上万位的话,每一位都要执行一遍,所用时间就很长了。

    2、最直接的优化方法,其实就是空间换时间的思想:可以预建立一个表,存放了从0~2^32每个数中1的个数,用时去查一下表就知道了。但这样显然要耗费很多的空间(至少2^32/(256/32)=512MB,哈哈,正是一般内存大小)。于是需要再优化:存放0-255每个数中1的个数,然后分段查询。如下面把32位数分为4段,每段一个字节,所以有一个256大小供查询的表: 

    char tOne[256]="\0\1\1\2\1\2……"; //后面省略 

    int findone(unsigned int n){
    for(int i=0;n>0;n>>=8) //每次右移8位将32位分成四段
    i+=tOne[n&255];
    return i;
    }

    3、上次在阿里云笔试,碰到一题也是求一个整数中1的个数。

    int func(unsigned int n){ 
      int count=0; 
      while(n>0){ 
        n&=(n-1); 
        count++; 
      } 
      return count; 
    }
    

    比如n=10,二进制为1010,count=2。  

    4、下面这种方法据说更快,但是我觉得不容易想出来。发现很多题目都可以用位运算来快速解决,可惜本人十分讨厌使用它,总觉得在绕来绕去的,伟大的位运算...

    int count_ones(unsigned a)
    {
    a = (a & 0x55555555) + ((a >> 1) & 0x55555555);
    a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
    a = (a & 0x0f0f0f0f) + ((a >> 4) & 0x0f0f0f0f);
    a = (a & 0x00ff00ff) + ((a >> 8) & 0x00ff00ff);
    a = (a & 0x0000ffff) + ((a >> 16) & 0x0000ffff);

    return a;
    }

    该代码的思路是这样的:2位2位为一组,相加,看看有几个1。再4位4位为一组,相加,看看有几个1......

    为了简单说明,先看看8位的情形。相应地,函数里面的语句变成。
    x = (x & 0x55) + ((x >> 1) & 0x55);    (1)
    x = (x & 0x33) + ((x >> 2) & 0x33);    (2)
    x = (x & 0x0f) + ((x >> 4) & 0x0f);    (3)
    return x;

    假设x=abcdefgh. 0x55=01010101
    x & 0x55 = 0b0d0f0h.   (x>>1) & 0x55 = 0a0c0e0g。相加。就可以知道2位2位一组1的个数。

    比如x=11111111
    x= (x & 0x55) + ((x >> 1) & 0x55); 之后x=10101010。你2位2位地看,10=2, 就是2 2 2 2, 就是说各组都是2个1。
    比如x=00101001
    x= (x & 0x55) + ((x >> 1) & 0x55); 之后x=00010101。你2位2位地看,就是0 1 1 1, 前1组只有0个1,后面的组都是1个1。

    好啦。再来看。0x33=00110011。
    x=abcdefgh. 
    x=(x & 0x33)+((x >> 2)&0x33); 相当于, 00ab00ef + 00cd00gh。
    因为语句(1)之后。ab指示了头两位有多少个1,cd指示了下两位有多少个1。相加00ab+00cd就指示前4位有多少个1。这样就是4位4位为一组。注意这样的分组,组与组之间永远都不会产生进位的。正因为不会产生进位,才可以分开来看。

    下面的过程都是一样的,不再多说。8位,16位,32位都一样。

  • 相关阅读:
    Ng-model undefined in the controller
    使用nvm进行node多版本管理
    AngularJS内置指令
    angularjs ng-switch
    Interpreting NotifyCollectionChangedEventArgs zz
    XAML控件不可访问,它具有一定的保护级别
    WPF RadioButton的绑定
    WPF中的ObservableCollection数据绑定
    C#语法中一个问号(?)和两个问号(??)的运算符是什么意思?zz
    python 获取mac地址zz
  • 原文地址:https://www.cnblogs.com/stoneJin/p/2224900.html
Copyright © 2011-2022 走看看