经典面试问题:统计二进制中1的个数
  WNNVLujRtYsY 2023年11月02日 80 0

统计二进制中1的个数是一道经典的面试题,常常被用来考察候选人对位操作和算法的理解。这个问题的来源可以追溯到计算机科学领域的早期。

第一种方法的思路是通过循环和除以2的操作来逐位判断一个整数的二进制表示中是否为1,并计算1的个数。下面是代码的简要思路说明:

  1. 首先,定义了一个函数 count_bit_one,该函数接受一个无符号整数 input 作为参数,用于计算二进制表示中1的个数。
  2. 在 count_bit_one 函数中,初始化计数器 count 为0。
  3. 进入循环,当 input 不为0时,执行以下操作:
  • 判断 input 除以2的余数是否为1,即判断二进制表示的最右边一位是否为1。
  • 如果余数为1,则将计数器 count 自增1,表示找到了一个1。
  • 将 input 除以2,相当于将二进制表示向右移动一位,去掉最右边的一位。
  1. 循环结束后,返回计数器 count 的值,即为二进制表示中1的个数。

代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

//计算1的个数
int count_bit_one(unsigned int input) {
	int count = 0;
	while (input) {
		if (input % 2 == 1)
			count++;
		input = input / 2;
	}
	return count;
}

	int main()
	{
		int input = 0;	//存放读入的数字
		printf("请输入一个整数:\n");
		scanf("%d", &input);
		int count = count_bit_one(input);//用于计算1的个数,并返回
		printf("%d转为二进制一共有%d个1\n", input, count);
	
	return 0;
}

需要注意的是:

count_bit_one函数中,使用 unsigned int类型是为了确保输入的整数是非负的。由于二进制表示中的最高位用来表示符号(0表示正数,1表示负数),因此使用unsigned int可以确保输入的整数只包含正数部分,而不会有负数的情况。

如果使用int类型,输入一个负数时,循环判断的条件while (input)会一直成立,导致无限循环。而使用unsigned int类型,当输入负数时,负数是以补码的形式存储的,其二进制表示的最高位为1,循环条件while (input)会在经过一次循环后判断为假,退出循环。


第二种方法是使用了按位与运算符(&)来判断二进制表示的最右边一位是否为1。按位与运算符将两个操作数的对应位进行逻辑与运算,只有当两个操作数的对应位都为1时,结果位才为1,否则为0。

在循环中,我们将input与1进行按位与运算,判断最右边一位是否为1。如果结果为1,则计数器count自增1,表示找到了一个1。然后,将input右移1位,相当于将二进制表示向右移动一位,去掉最右边的一位。

循环结束后,返回计数器count的值,即为二进制表示中1的个数。

你可以调用这个函数并传入一个无符号整数,它将返回该整数的二进制表示中1的个数。

代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
//按位与求二进制中1的个数
int count_bit_one(unsigned int input) {
    int count = 0;
    while (input) {
        if (input & 1)	//最右位是1,计数器加1
            count++;
        input >>= 1;  // 右移1位
    }
    return count;
}


	int main()
	{
		int input = 0;	//存放读入的数字
		printf("请输入一个整数:\n");
		scanf("%d", &input);
		int count = count_bit_one(input);//用于计算1的个数,并返回
		printf("%d转为二进制一共有%d个1\n", input, count);
	
	return 0;
}



第三种方法也是最经典的方法:"Brian Kernighan's Algorithm"(布赖恩·克尼根算法)

该算法通过不断将整数的最右边的1置为0,直到整数变为0,同时计数置为1的次数。

布赖恩·克尼根算法(Brian Kernighan's Algorithm)是一种用于计算二进制表示中1的个数的经典算法。该算法由计算机科学家布赖恩·克尼根(Brian Kernighan)提出,并被广泛应用于计算机领域。

算法的基本思想是利用位操作技巧,通过不断将整数的最右边的1置为0来计算1的个数。它的核心观察结果是:对于任意的整数n,n与(n-1)进行按位与运算,可以将n的二进制表示中的最右边的1置为0。

以下是布赖恩·克尼根算法的步骤:

  1. 初始化一个计数器count为0。
  2. 循环直到整数n变为0:
  • 将n与(n-1)进行按位与运算,结果赋值给n。
  • 计数器count增加1。
  1. 返回计数器count的值,即为二进制表示中1的个数。

在每次循环中,n与(n-1)的按位与运算会将n的最右边的1及其右边的所有位都置为0,而保持其他位的值不变。通过不断执行这个操作,直到n变为0,我们可以计算出二进制表示中1的个数。

举个例子:

当我们使用布赖恩·克尼根算法计算二进制中1的个数时,让我们以一个整数10(二进制表示为1010)为例。下面是使用该算法计算1的个数的步骤:

  1. 初始化计数器count为0。
  2. 循环直到整数n变为0:
  • 将n与(n-1)进行按位与运算,结果赋值给n。
  • 计数器count增加1。

初始状态:

  • n = 10 (二进制:1010)
  • n - 1 = 9 (二进制:1001)
  • count = 0

第一次循环:

  • n = n & (n-1) = 10 & 9 = 8 (二进制:1000)
  • n - 1 = 7 (二进制:0111)
  • count = 1

第二次循环:

  • n = n & (n-1) = 8 & 7 = 0 (二进制:0000)
  • count = 2

循环结束,最终结果:

  • count = 2

因此,整数10的二进制表示中有2个1。

这个例子展示了布赖恩·克尼根算法如何通过不断将整数的最右边的1置为0来计算二进制中1的个数。通过按位与运算和计数器的累加,我们可以高效地获得结果。

布赖恩·克尼根算法的优点在于,它的运行时间仅取决于整数中1的个数,而不是整数的位数。因此,对于具有大量位的整数,该算法比遍历所有位的方法更高效。


以下是使用布赖恩·克尼根算法计算二进制中1的个数的示例代码:

int count_bit_one(unsigned int input) {
    int count = 0;
    while (input) {
        input = input & (input - 1);
        count++;
    }
    return count;
}


	int main()
	{
		int input = 0;	//存放读入的数字
		printf("请输入一个整数:\n");
		scanf("%d", &input);
		int count = count_bit_one(input);//用于计算1的个数,并返回
		printf("%d转为二进制一共有%d个1\n", input, count);
	
	return 0;
}

在这个算法中,我们使用了一个关键的位操作:input = input & (input - 1)。这个操作会将input的最右边的1置为0,同时保留其他位的值不变。通过不断执行这个操作,直到input变为0,我们可以计算出二进制表示中1的个数。

在循环中,我们将input(input - 1)进行按位与运算,得到的结果赋值给input。这个操作会将input的最右边的1及其右边的所有位都置为0。因此,每执行一次这个操作,就相当于消去了一个1,计数器count增加1。

循环结束后,返回计数器count的值,即为二进制表示中1的个数。







【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论