深度剖析求一个数中的二进制位中的1的个数的多种方法

   方法一:我们都知道,要取出一个整数的每一位,最简单的算法逻辑为 :模10;除10.
  例如:假如要输出 1234 这个数的每一位;算法如下:

#include<stdio.h>
int main()
{
    int num = 0;
    printf("请输入:");
    scanf("%d",&num);
    while(num)//123
    {
        int k =0;
      k = num % 10;
      printf("%d ",k);
      num = num /10;
    }
   return 0;
}

输出结果为

  可以看出用 模10;除10 这种方法是可以取出一个整数的每一位的;虽然运行结果是倒叙输出的,我会在后期采用递归的算法正序输出,由于在这里这不是重点,就不在详细演示递归的方法了。
  由上述过程我们可以得到一些启发:求一个二进制位中1的个数 ,我们可以采用 模2,除2来计算。算法如下:

#include<stdio.h>
int main()
{   
    int count = 0;
    int num = 0;
    scanf("%d",&num);
    while(num)
    {
    if(num % 2 ==1)
    {
       count ++;
    }
    num = num/2;//取十进制位的每一位为  %10  /10  ;所以取二进制为的每一位为 %2  /2;
    }
    printf("%d",count);
  return 0;
}

结果如下

  通过以上结果,发现我们所写的代码似乎是没有问题的,但是如果输入一个负数,还会输出正确的结果吗?
结果如下:

  通过结果,我们发现 -1中1的个数为0;显然是错误的,我们都知道-1中1的个数为32。所以上述的代码是有问题的。
  代码改进如下:

int main()
{   
    int count = 0;
    int unsigned num = 0;
    scanf("%d",&num);
    while(num)
    {
    if(num % 2 ==1)
    {
       count ++;
    }
    num = num/2;
    }
    printf("%d",count);
  return 0;
}

  结果如下:

改进方法:在第四行定义了一个无符号的整型

方法二
  分析:我们都知道,数据在计算机中的存储方式都为二进制形式,一个整型的字节数为4(32位机器),即三十二个bite位。我们可以通过循环把一个数的三十二位取出来依次和1相与,如果结果为1;采用一个 count 变量加一。
  算法如下:

#include<stdio.h>
int one_bite(unsigned int x )
{
    int  i = 0;
    int count = 0;
    for( i = 0; i < 32; i++)
    {
      if(((x>>i) & 1) == 1)
     {
         count ++; 
      }
    }
    return count;
}
int main()
{
    unsigned int n = 0;
    scanf("%d",&n);
    printf("%d\n",one_bite(n));
  return 0;
}

结果如下:

  代码分析:虽然结果正确,但是这个代码是繁琐的,需要循环三十二次,才能得到最后结果,效率不高。因此采用方法三;可以使代码执行效率更高。
方法三
  分析:假设一个数字为15;它的二进制位为:
      15: 00000000 00000000 00000000 00001111
   (15-1): 00000000 00000000 00000000 00001110
 二者取与运算: 00000000 00000000 00000000 00001110 (14)
14在和(14-1)与运算结果:00000000 00000000 00000000 00001100 (12)
……
以此类推
最后8和(8-1)与运算结果为:00000000 00000000 00000000 00000000
从上述运算规律可以看出:每次取完后的num都会和(num-1)相与;将相与的值赋给num;直到num的值为0;结束算法。代码如下:

#include<stdio.h>
int main()
{
    int num = 0;
    int count = 0;
    scanf("%d",&num);
    while(num)
    {
      num = num & (num-1);
      count ++;
    }
    printf("%d",count);
  return 0;
}

结果如下:

代码分析:代码精简,而且效率高。为求这道题的最佳方法。

全部评论

相关推荐

孤寡孤寡的牛牛很热情:为什么我2本9硕投了很多,都是简历或者挂,难道那个恶心人的测评真的得认真做吗
点赞 评论 收藏
分享
10-28 11:04
已编辑
美团_后端实习生(实习员工)
一个2人:我说几个点吧,你的实习经历写的让人觉得毫无含金量,你没有挖掘你需求里的 亮点, 让人觉得你不仅打杂还摆烂。然后你的简历太长了🤣你这个实习经历看完,估计没几个人愿意接着看下去, sdk, 索引这种东西单拎出来说太顶真了兄弟,好好优化下简历吧
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务