要求:写一个函数返回参数二进制中 1 的个数。
比如: 15 0000 1111 4 个 1
一.除二判断法
第一种方法比较简单,就是把这个数除以二,判断是否为1,满足条件,就加1;然后在除以2,(如果是10进制的话除以10,2进制除以2);
int num(unsigned int i)
{
int count = 0;
while (i)
{
if (i % 2 == 1)
{
count++;
}
i = i / 2;
}
return count;
}
二.按位相与法
计算机中存储数据的一般是32位补码,所以要和1相与32次;但这个算法效率比较低,因为不管是什么数都要比较32次;
比如15&1=1 所以count++;
000000000000000000001111
000000000000000000000001
然后15在向右移动1位,就是7&1=1,所以count++;
000000000000000000000111
000000000000000000000001
然后7在向右移动1位,就3&1=1,所以count++;
000000000000000000000011
000000000000000000000001
然后3在向右移动1位,就1&1=1,所以count++;
000000000000000000000001
000000000000000000000001
然后在移动1位就成0了,所以跳出循环。
int num(int i)
{
int count = 0;
int n;
for (n = 0; n < 32; n++)
{
if (((i >> n) & 1) == 1)
{
count++;
}
}
return count;
}
三.减1相与法
拿7(111)举例子;
第一次 111&110=110,这次就可以成功的把从低位起第一个1消掉了,同时计数器加1。
第二次110&101=100,这次就可以成功的把从低位起第一个1消掉了,同时计数器加1。
第三次100&011=000,同理又统计了高位的一个1,此时n已变为0,不需要再继续了。
所以这样统计下7里面就有3个1;
int num(int i)
{
int count = 0;
while (i)
{
i = i & (i - 1);
count++;
}
return count;
}
同理,我们也可以用这种方法来求一个数是不是2的次方数
16&15=0 所以16是2的次方数
00000000000000000010000
00000000000000000001111
if ((i & (i - 1)) == 0)
{
printf("是2的次方数");
}
else
{
printf("不是2的次方数");
}
四.整体代码
#include<stdio.h>
// 1.除二判断法
int num(int i)
{
int count = 0;
int n;
for (n = 0; n < 32; n++)
{
if (((i >> n) & 1) == 1)
{
count++;
}
}
return count;
}
//2.按位相与法
int num(unsigned int i)
{
int count = 0;
while (i)
{
if (i % 2 == 1)
{
count++;
}
i = i / 2;
}
return count;
}
//3.减1相与法
int num(int i)
{
int count = 0;
while (i)
{
i = i & (i - 1);
count++;
}
return count;
}
int main()
{
int i;
scanf("%d", &i);
int ret = num(i);
printf("%d ", ret);
}