判断32位整数二进制中1的个数

在面试中被问到这一题:判断32位无符号整数二进制中1的个数,虽然不难,但要求层层优化。现在整理一下:
1、基本思路:

#include  < iostream >  
 
using   namespace  std; 
 
int  findone(unsigned  int  n) ...  
 
int  main()
  
int n; 
  cin
>>n; 
  cout
<<findone(n)<<endl; 
  
return 0
}
 

 

2、优化:
这样的时间复杂度是T(m)=m,取决于二进制数的位数m。如果要求在更短时间内求出,应该如何做呢?如果findone函数被反复调用(成千上万次调用),那应该怎么优化呢?
其实就是空间换时间的思想:可以预建立一个表,存放了从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)
    i
+=tOne[n&255];
  
return i;
}

3、据说Intel中有条汇编指令(或是数条)即可完成这个工作,但不知道具体是什么,应该怎样做。

unsigned  int  func(unsigned  int  x)
{
    x 
= (x & 0x55555555UL+ ((x >> 1& 0x55555555UL); // 0-2 in 2 bits
    x = (x & 0x33333333UL+ ((x >> 2& 0x33333333UL); // 0-4 in 4 bits
#if 1
    
// Version 1
    x = (x & 0x0f0f0f0fUL+ ((x >> 4& 0x0f0f0f0fUL); // 0-8 in 8 bits
    x = (x & 0x00ff00ffUL+ ((x >> 8& 0x00ff00ffUL); // 0-16 in 16 bits
    x = (x & 0x0000ffffUL+ ((x >> 16& 0x0000ffffUL); // 0-31 in 32 bits
    return x;
#else
    
// Version 2
    x = (x + (x >> 4)) & 0x0f0f0f0fUL// 0-8 in 4 bits
    x += x >> 8// 0-16 in 8 bits
    x += x >> 16// 0-32 in 8 bits
    return x & 0xff;
#endif
}


4、又看到有道MS的笔试题殊途同归:

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

  
return count;
}

 

 

你可能感兴趣的:(优化,工作,面试,汇编,n2)