【C语言练习】 二进制中1的个数

news2024/11/26 14:31:47

在这里插入图片描述在这里插入图片描述


目录

  • 题目详情:
  • 思路一:
  • 思路二:
  • 思路三:

题目详情:

在这里插入图片描述

思路一:

 拿到二进制的每一位,看它是否等于 1 1 1,再定义一个计数器变量,如果等于 1 1 1,计数器变量就加 1 1 1。最终计数器的值就是 1 1 1 的个数。
 现在的问题就变成了—— **如何得到二进制的每一位?**以十进制数字 123 123 123 为例,通过123%10=3 就能得到 3 3 3,不难发现:只要用一个数除以它的进制数,最终的余数就是这个数最低位上的数字,因此如果要得到 2 2 2 首先要让 2 2 2 来到最低位,只要去掉当前最低位上的 3 3 3 2 2 2 就能来到最低位上。如何去掉最低位上的数字呢? 通过 123/10=13 就能把最低位上的 3 3 3 去掉。可见:只要用一个数除以它的进制数,就能去掉该数当前的最后一位数字。(这里指的是整数除法)因此我们只要不断地重复上面的两个步骤,就能都得到一个数上的每一位数字。二进制数也同理。思路整理的差不多接下来就该通过代码来实现了。

代码实现:

int NumberOf1(int a)
{
	int count = 0;//计数器
	while (a)
	{
		if (a % 2 == 1)//通过取模得到最低位上的数字
		{
			count++;
		}
		a /= 2;//通过整数除法取出掉最低位上的数字
	}
	return count;
}

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

上述代码缺陷:
 经过测试发现,上述代码可以准确计算出一个正整数二进制位中 1 1 1 的个数,当参数是负数时,计算出来的结果,与我们希望的结果会有很大的差距。以 − 1 -1 1 为例,理论上 − 1 -1 1 的补码是32个全 1 1 1 ,因此计算出来的结果应该是32才对,但上面这段代码计算出的结果是 0 0 0 ,为什么呢?结果是 0 0 0 说明 if (-1 % 2 == 1) 没成立过,我们可以通过内存窗口来看看-1 % 2的结果到底是什么,

在这里插入图片描述
 结果是 ff ff ff ff。内存中存的是补码,所以对应的二进制补码就是 11111111111111111111111111111111 11111111111111111111111111111111 11111111111111111111111111111111int b 说明 b 是一个有符号的的整型,因此前面二进制的最高位是符号位,并且是 1 1 1 ,说明 -1%2 的结果是一个负数,自然就不可能等于 1 1 1 了。我们发现:只要是一个负数,对 2 2 2 取模得到的结果就一定是一个负数,就永远也不可能等于 1 1 1,如何解决这个问题呢?
 这里我们可以把形参设置成一个无符号的整型变量,此时问题就迎刃而解了。还是以 − 1 -1 1 为例: − 1 -1 1 在内存中的补码是 11111111111111111111111111111111 11111111111111111111111111111111 11111111111111111111111111111111 传参的时候用一个无符号的整型变量 a 去接收 ,在这个无符号的整型变量 a 的眼里 11111111111111111111111111111111 11111111111111111111111111111111 11111111111111111111111111111111 就不再是什么 − 1 -1 1 的补码了,a 认为这就是一串普普通通的二进制代码,没有什么所谓的符号位这些乱七八糟的东西。因此再用 a%2 得到的结果就不再可能是负数了,我们还是可以通过调试来一探究竟。

在这里插入图片描述
 上图中,我们把 − 1 -1 1 赋值给一个无符号的的整型变量 a ,然后用 a%2 得到的结果是 1 1 1 ,并且也是无符号整型;用 a/2 得到 2147483647 2147483647 2147483647 ,这个很容易理解,因为 − 1 -1 1 的补码 11111111111111111111111111111111 11111111111111111111111111111111 11111111111111111111111111111111a 的眼里就是一个平平无奇的二进制序列,没有符号位,这个二进制序列转换成十进制就是: 4 , 294 , 967 , 295 4,294,967,295 4,294,967,295,除以 2 2 2 就得到 2147483647 2147483647 2147483647

在这里插入图片描述
代码修改:

int NumberOf1(unsigned int a)//把形参改成无符号整型,就对负数也适用了
{
	int count = 0;
	while (a)
	{
		if (a % 2 == 1)
		{
			count++;
		}
		a /= 2;
	}
	return count;
}

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

 上面的代码,在传 − 1 -1 1 的时候,计算出来的结果就是我们所期待的 32 32 32 了。到这里,思路一就结束了。接下来看另一种思路。

思路二:

 思路二的答题思想和思路一 一样,得到二进制序列的每一位,然后看其是否等于 1 1 1 。只不过思路二的实现方法与思路一不同,会比思路一容易一些,都是初学者不容易想出来。接下来就来整理一下思路二吧,首先我们还是希望得到二进制的每一位,此时我们可以借助按位与( & )这个操作符来实现,还记得按位与的计算过程嘛?对应的两个二进制位都为 1 1 1 的时候出 1 1 1 ,其他全部出 0 0 0 ,因此,可以让待求得二进制序列按位与 1 1 1 , 1 1 1 的二进制序列为 00000000000000000000000000000001 00000000000000000000000000000001 00000000000000000000000000000001 ,此时待求的二进制序列的最低位如果是 1 1 1 ,那 1&1 得到的结果就是 1 1 1 ,如果待求的二进制序列的最低位是 0 0 0 ,那 0&1 得到的结果就是 0 0 0,我们发现任何一个二进制只要与上 1 1 1 都会得到它自身。此时我们得到了二进制序列的最低位,那它的第二位、第三位、第四位……呢?别忘了,我们还有一个移位操作符,我们可以利用移位操作符,让二进制序列往右移动,使得每一个二进制位都能与上 1 1 1 ,这样我们就能拿到二进制序列的每一位了。大体思路捋的差不多了,接下来该上代码了。

int NumberOf1(int a)
{
	int i = 0;
	int count = 0;
	for (i = 0; i < 32; i++)//最多只需右移31个二进制位
	{
		if (((a >> i) & 1) == 1)//只有当1 & 1结果才是1,让a的二进制位一直右移
		{
			count++;
		}
	}
	return count;
}

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

 思路二也无需考虑什么正负数,因为移位操作符和位操作符都是直接针对二进制位来计算的,看完思路二我就只想说。但是别急,接下来的思路三才算得上是“王炸”

思路三:

 这里直接上方法,记住下面这个式子:n=n&(n-1) 。举个例子,以十进制的 11 11 11 为例, 11 11 11 的二进制是 1011 1011 1011 ,此时 n=1011;n-1=1010;n&(n-1)=1010 此时 n 就变成了: 1010 1010 1010 ,对比前面的 n 我们发现二进制序列最右边的 1 1 1 变成了 0 0 0 ,接着往下,n=1010;n-1=1001;n&(n-1)=1000此时 n就变成了 1000 1000 1000 对比第二个 n 二进制序列最右边的 1 1 1 又变成了 0 0 0,再往下看,n=1000;n-1=0111;n&(n-1)=0000 此时 n 就变成了 0000 0000 0000 。不难发现:n 从最初的 1011 1011 1011 ,变成了现在的 0000 0000 0000 是把n=n&(n-1)这个式子执行了 3 3 3 次,什么?3??这不就是 1011 1011 1011 这个二进制序列里面 1 1 1 的个数嘛,其实这并非偶然,因为n=n&(n-1) 这个式子每执行一次,就会把当前 n 这个二进制序列里面最右边的 1 1 1 去除掉,直到整个二进制序列变成 0 0 0 ,分析的差不多了,接下来上代码!

int NumberOf1(int n)
{
	int count = 0;
	while (n)//能变成全0的时候,就不用再执行下面的式子了
	{
		n = n & (n - 1);
		count++;//记录上面这个式子一共执行了多少次
	}
	return count;
}

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

 哈哈,没骗你吧,思路三才是最终的“王炸”

 好了,这道题的分享就到这里啦,如果你有更好的思路或者方法,欢迎在评论区或者私信,给我留言,拜拜咯!


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rancher的k3s证书过期

文章目录现象rancher报错日志分析解决思路解决现象 web上rancher不能访问&#xff0c;服务上看443端口没了&#xff0c;6443端口仍然在。 rancher报错日志 rancher | time"2023-01-05T01:56:07.241615176Z" levelinfo msg"Waiting for master node start…

代码随想录--数组相关题目整理

LeetCode数组相关题目整理 1. LeetCode704 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 解题思路&#xf…

亚马逊云科技助力游戏上云学习心得-运行篇

云服务已经是大势所趋了&#xff0c;通过购置传统服务器来进行应用开发&#xff0c;无法与现代化敏捷的开发方法相结合&#xff0c;对于系统运维的难度也大大增加&#xff0c;而云服务的弹性伸缩、动态计费可以很好地帮助中小企业实现快速应用开发&#xff0c;使得产品的价值最…

一文吃透python面向对象基础+进阶

目录基本理论面向过程与面向对象面向过程面向对象基本概念面向对象基本语法定义类创建对象属性属性和变量区别对象属性类属性限制对象属性添加方法实例方法类方法静态方法私有属性只读属性私有方法魔法方法字符串表示可调用索引操作切片操作比较操作布尔判断遍历操作面向对象三…

字节青训营Go语言学习第一天--基础语言+实战案例

文章目录走进Go语言基础语言2.2基础语言-变量2.3基础语法- if else2.4基础语法-循环基础语法-switch基础语法-数组基础语法-切片基础语法-map基础语法-range基础语法-函数基础语法-指针基础语法-结构体基础语法-结构体方法基础语法-错误处理基础语法-字符串操作基础语法-字符串…

通讯录升级--可增容(动态增长空间)

通讯录成员的改变 之前我们定义了date[100]的数组用来存放100个人的信息&#xff0c;但是当需要存储的人数超过100时&#xff0c;内存不够&#xff0c;存储人数较少时&#xff0c;又有些浪费&#xff0c;并且数组空间在创建时就已经确立&#xff0c;无法随需求改变&#xff0c…

rabbitmq+netcore6 【6】RPC:远程过程调用

文章目录1&#xff09;前言2&#xff09;Client interface 客户接口3&#xff09;Callback queue回调队列4&#xff09;Correlation Id 关联Id5&#xff09;Summary总结6&#xff09;综合以上代码准备工作服务端客户端结果验证官网参考链接&#xff1a; https://www.rabbitmq.c…

372. 超级次方

372. 超级次方题目算法设计&#xff1a;迭代算法设计&#xff1a;递归题目 传送门&#xff1a;https://leetcode.cn/problems/super-pow/ 题目不难懂&#xff0c;问题在于 b 是一个非常非常大的数&#xff0c;会溢出。 迭代和递归&#xff0c;各有解决方法&#xff0c;记录在…

Elasticsearch入门——kibanna和postman操作Elasticsearch索引示例

目录一、使用kibanna操作Elasticsearch索引示例二、使用postman操作Elasticsearch索引示例三、kibanna和postman操作Elasticsearch的总结一、使用kibanna操作Elasticsearch索引示例 启动Elasticsearch和kibanna服务&#xff0c;浏览器访问http://localhost:5601/,进入Dev Tools…

week11

T1汤姆斯的天堂梦 题目描述 汤姆斯生活在一个等级为 000 的星球上。那里的环境极其恶劣&#xff0c;每天 121212 小时的工作和成堆的垃圾让人忍无可忍。他向往着等级为 NNN 的星球上天堂般的生活。 有一些航班将人从低等级的星球送上高一级的星球&#xff0c;有时需要向驾驶…

【C语言】数据结构基础(每日小细节025),有三数之和哦

算法好题初阶&#xff08;一共14回已经更新完毕&#xff09;&#xff0c;从今天开始就是基础的数据结构题目 1.只出现一次的数字 如果不额外开辟任何空间的话一定要想到位运算符 异或^ :两个整数异或&#xff0c;遵循相同为0&#xff0c;相异为1的二进制位运算规则 &#x…

【Nginx 基础】

Nginx 的安装 Nginx 的静态网站部署 理解 Nginx 的反向代理与负载均衡&#xff0c;能够配置反向代理与负载均衡 一、 Nginx 概述 Nginx 是一款高性能的 HTTP 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;由俄罗斯的程序工程师伊戈…

spring学习系列

Spring_三种方式的依赖注入1.第一种&#xff0c;set方式&#xff0c;property2.构造器注入&#xff08;构造方法&#xff09;3.p命名空间注入4、注入各种数据类型//老师类 public class Teacher {private String name;private int age; }//课程类 public class Course {private…

云原生技术学习笔记(基础版)

一、容器基本概念容器运行时&#xff0c;多种虚拟化技术&#xff0c;runC、kata、gVisor等。containerd -shim不是个lib&#xff0c;是个守护进程&#xff0c;管理容器生命周期,可被containerd动态接管。&#xff08;可以从containerd中脱离出来&#xff0c;插件化管理&#xf…

jvm系列(1)--JVM和Java体系架构

目录Java-跨平台的语言JVM-跨语言的平台多语言混合编程虚拟机虚拟机概念Java虚拟机JVM的位置JVM的整体结构Java代码执行流程JVM的架构模型基于栈的指令集架构基于寄存器的指令级架构两种架构的举例JVM架构总结JVM的生命周期虚拟机的启动虚拟机的执行虚拟机的退出Java-跨平台的语…

VTK-vtkSelectPolyDataFilter

前言&#xff1a;本博文主要记录vtkSelectPolyDataFilter接口的应用&#xff0c;实现原理&#xff0c;以及与其近似的vtkClipPolyData&vtkImplicitSelectionLoop的应用相比较&#xff0c;帮助小伙伴理解vtkSelectPolyDataFilter接口的实现原理&#xff0c;并且与其它接口进…

2023新生个人训练赛第08场解题报告

问题 A: Candies 题目描述 We have a 2N grid. We will denote the square at the i-th row and j-th column (1≤i≤2, 1≤j≤N) as (i,j). You are initially in the top-left square, (1,1). You will travel to the bottom-right square, (2,N), by repeatedly moving ri…

鉴源论坛 · 观通丨轨交系统安全性设计

作者 | 刘艳青 上海控安安全测评中心安全测评部测试经理 版块 | 鉴源论坛 观通 引语&#xff1a;第一篇对轨交信号系统从铁路系统分类和组成、城市轨交系统分类和组成、城市轨交系统功能、城市轨交系统发展方面做了介绍&#xff0c;第二篇从信号基础出发&#xff0c;讲述了信…

【蓝桥杯算法 1】AcWing166.飞行员兄弟

本文已收录专栏 &#x1f332;《蓝桥杯周训练》&#x1f332; “飞行员兄弟”这个游戏&#xff0c;需要玩家顺利的打开一个拥有 16 个把手的冰箱。 已知每个把手可以处于以下两种状态之一&#xff1a;打开或关闭。 只有当所有把手都打开时&#xff0c;冰箱才会打开。 把手可…

支持数位板的远程软件,实现远程使用 Wacom 数位板

现在数位板越来越流行了&#xff0c;影视、动漫、游戏、设计等行业经常需要用到。Wacom 是数位板领域的全球领导者&#xff0c;其设备为创意人员带来了真正的纸感绘图体验。 数位板用户需要远程办公的时候&#xff0c;经常会遇到两个问题&#xff1a;远程软件不支持数位板、远…