写一个函数返回参数二进制中1的个数(包含原码反码补码的理解、移位操作符的使用、按位与、按位或、按位异或)

目录

题目:

准备:

方法一(只针对正数):

思路:

题解:

方法二(正负数通用):

前言:

首先,我们来了解一下原码反码与补码:

 其次,我么来了解一下移位操作符<< >>:​

最后,我们再了解一下位操作符& | ^:

按位与 &:

​按位或 |:  

按位异或 ^:​

 小结: 

思路:

题解:

方法三(方法二的优化)

思路:

 题解:



题目:

写一个函数返回参数二进制中 1 的个数。

比如: 15    0000 1111    4 个 1

牛客网的OJ链接

准备:

创建一个函数:

#include<stdio.h>

int CountOne(int num)
{

}

int main()
{
	int num = 0;
	scanf("%d", &num);
	int ret = CountOne(num);
    printf("%d\n",ret);
	return 0;
}

方法一(只针对正数):

思路:

当我们要计算十进制参数的某个数个数时,我们可以采取取模运算让参数%10,

从而得到参数的最后一位,接着在对参数/10,然后再进行取模运算...

在二进制中,我们也可以用同样的方法,需要让参数%2,

就可以得到参数的最后一位数字,再让参数/2,然后再进行取模运算...

我们先来看如何计算十进制中1的个数:

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

题解:

以此类推,我们可以写出计算二进制中1的个数:

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

 对比一下,不难看出,只是把 % 和 / 后的数改了一下,同理,也可以这样进行八进制中某个数字的个数。

方法二(正负数通用):

前言:

首先,我们来了解一下原码反码与补码:

 其次,我么来了解一下移位操作符<< >>:

 当然,电脑都是将整型的补码进行移位的。

最后,我们再了解一下位操作符& | ^:

按位与 &:


按位或 |:  

按位异或 ^:

 小结: 

知道了这些,我们就可以得到一些小结论:

a&1=1        a|0=a        a^0=a        a^a=0

思路:

通过移位操作符,我们可以求得参数二进制的每一位,从而确定每一位的结果是不是1。

题解:

我们可以想到每次都让参数移动1位,然后让其按位与1,判断其值是否为1,但是我们也知道移位操作符不会改变参数的值,所以我们就可以每次让参数移动 i 位,每次移动完 i 都会+1

int CountOne(int num)
{
	int count = 0;
	for (int i = 0; i < 32; i++)
	{
		if ((num >> i) & 1) 
			count++;
	}
	return count;
}

方法三(方法二的优化)

思路:

从方法二我们可以知道,任何时候都要循环32次,那么如何优化它呢?其实这里用到了很巧妙的方法:

二进制序列n变成n-1时,最末尾的1就会变成0,当n&(n-1)时,因为末尾数字不同,所以就会把最末尾的1变成0,循环往复,直到n为0时,停止循环。我们以15为例:

 题解:

int CountOne(int num)
{
	int count = 0;
	while (num)
	{
		count++;
		num = num & (num - 1);
	}
	return count;
}

猜你喜欢

转载自blog.csdn.net/m0_75186846/article/details/131991699