二进制中1的个数

  • 算法-求二进制数中1的个数  
  • 问题描述  
  • 任意给定一个32位无符号整数n,求n的二进制表示中1的个数,比如n = 5(0101)时,返回2,n = 15(1111)时,返回4  
  •   
  • 这也是一道比较经典的题目了,相信不少人面试的时候可能遇到过这道题吧,下面介绍了几种方法来实现这道题,相信很多人可能见过下面的算法,但我相信很少有人见到本文中所有的算法。如果您上头上有更好的算法,或者本文没有提到的算法,请不要吝惜您的代码,分享的时候,也是学习和交流的时候。

method1:
将二进制数byte v mod 2得到该二进制数中的最末尾一位,若为1则计数加1,否则为0。将二进制数除以2得到新的二进制数,将其赋给v,循环操作。
当得到的v中没有1即v==0时跳出循环。返回计数值即为二进制中1的个数。此算法时间复杂度为O(logv)。

int count(int  v){
      int num=0;
   while(v){
    if(v%2==1){
              num++;
    }
    v=v/2;
   }
   return num;
}


method2:
由于采用位操作比余操作的效率高很多,故在此采用位操作。但是时间复杂度仍为O(logv)。
将二进制数右移一位如10100010右移一位得到1010001,抛弃了最末尾一位。为了得到最末尾一位,将二进制数先与1进行与操作,若二进制数末尾为1,
与1与操作后结果为1。否则结果为0。直接将得到的结果加到计数变量上即可(若结果为0,加0不影响计数。若结果为1,加1则计数+1)。然后再将原
二进制数右移一位得到新的二进制数,直到新的二进制数为0,跳出循环。返回计数结果。

int count1(int v){
      int num=0;

   while(v){
    num+=v&0x01;
    v=v>>1;
   }
   return num;
}

method3:
为了简化这个问题,考虑只有一个1的情况。例如:01000000.
要判断给定的二进制数中只有一个1,可以进行如下的操作:
01000000 & (01000000-0x01)=01000000&00111111=0
这样可以将该二进制中的1消除掉。再扩展到有多个1的情况。对于二进制数byte v:
每进行一次v&=(v-1)将最低位的1变换成为0,计数器同时加1,直到v==0为止。
该算法的时间复杂度为O(M),M为二进制中1的个数。

int count2(int v){
     int num=0;
  while(v){
          v&=(v-1);
    num++;
  }
  return num;
}

method4:
由于只有8位数据,于是可以直接将0-255的情况存储起来,并使用分支操作。
该算法通过空间换时间来获取高的时间效率,最好情况下时间复杂度为O(1),最坏情况下时间复杂度为O(255),故解法不可取。

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 count4(int v){
   return countTable[v];
}

扩展问题
1. 如果变量是32位的DWORD,你会使用上述的哪一个算法,或者改进哪一个算法?
2. 另一个相关的问题,给定两个正整数(二进制形式表示)A和B,问把A变为B需要改变
多少位(bit)?也就是说,整数A 和B 的二进制表示中有多少位是不同的?

将A和B进行异或操作,相同为0,不同为1,操作后的结果中1的个数即代表AB二进制表示中有多少位不同。
设C=A^B,将问题转换为求C(二进制表示)中1的个数。采用method3即可求解。

#include<iostream>
#include "windows.h"

using namespace std;

int count5(int v){
     int num=0;
  while(v){
           v&=(v-1);
     num++;
  }
  return num;
}
int main(){
     int A,B;
  byte a,b,c;
  while(true){
          cin>>A>>B;
    c=A^B;
    int result=count5(c);
    cout<<"需要改变 "<<result<<" 位。"<<endl;
  }
  system("pause");
}
原文地址:https://www.cnblogs.com/yanglf/p/2714899.html