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

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

【IT168知识库】
 

在面试中被问到这一题:判断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;
}
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中有条汇编指令(或是数条)即可完成这个工作,但不知道具体是什么,应该怎样做。
4、又看到有道MS的笔试题殊途同归:
int  func(unsigned  int  n) {
  
int count=0;
  
while(n>0){
    n
&=(n-1);
    count
++;
  }

  
return count;
}

程序如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>

int count=0x7FFFFFFF;

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
}

int one_in_char[256];
int func2(int *v)
{
    unsigned char *ptr=(unsigned char *)v;
    return one_in_char[ptr[0]]+one_in_char[ptr[1]]+one_in_char[ptr[2]]+one_in_char[ptr[3]];
}

void test_1()
{
  int t1, t2;
  int i, v;
   char v2=0;
  t1 = time(NULL);
  for (i=0; i<count; i++)
    {
      v = func(i);
       v2+=v; /* 若不加这个,v 没使用,循环被优化掉了 */
    }
  t2 = time(NULL);
  printf("time of func: %d   v2=%d\n", t2-t1, v2);
}

void test_2()
{
  int t1, t2;
  int i, v;
   char v2=0;
  for (i=0; i<256; i++)
    one_in_char[i]=i%8;  /* 这 256 为硬编码, 为简便起见,随便设,不影响计算时间 */
  t1 = time(NULL);
  for (i=0; i<count; i++)
    {
      v = func2(&i);
       v2+=v; /* 若不加这个,v 没使用,循环被优化掉了 */
    }
  t2 = time(NULL);
  printf("time of func2: %d   v2=%d\n", t2-t1, v2);
}

int main(int argc, char **argv)
{
  test_1();
  test_2();
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值