[c语言日寄](bit)位检查——初探字节之下

news2025/1/18 16:18:37

哈喽大家好啊,在今天的快乐刷题中,我遇到了一个很有意思的题目:

题目

统计二进制中1的个数

基本思路

没错……这道题的对象比较特殊。
不同于过去常见的题目,之前的题目的对象都是基本数据类型,而这道题的对象却是基本数据类型之下——bit,也就是位。

位(bit)

“bit”是“binary digit”的缩写,中文意思是位。它是计算机中表示数据的最小单位,每个0或1就是一个位,而8个bit组成一个字节(Byte)。
在C语言中,没有直接的bit型变量类型,但可以通过位域(bit fields)或位运算来模拟bit型变量的定义(通过结构体)。

想要进行对位的操作,就需要以位为对象的专用运算符。

常见位运算符

  • 按位与(&)
    功能:两个相应的二进制位都为1时,结果才为1,否则为0。

  • 按位或(|)
    功能:两个相应的二进制位中只要有一个为1,结果就为1,否则为0。

  • 按位异或(^)
    功能:两个相应的二进制位相异时,结果为1,相同则为0。
    可以用于交换两个变量的值。
    点击此处查看往期内容:整数交换的三种方式。

  • 按位取反(~)
    功能:对二进制位取反,即0变1,1变0。

  • 左移(<<)
    功能:将二进制位向左移动指定的位数,左边移出的位被丢弃,右边空出的位用0填充。
    可以用于快速实现乘以2的幂次方的操作, x << n 相当于 x * 2^n。

  • 右移(>>)
    功能:将二进制位向右移动指定的位数,对于无符号数,左边空出的位用0填充;对于有符号数,左边空出的位用符号位填充(即符号扩展)。
    可以用于快速实现除以2的幂次方的操作,例如 x >> n 相当于 x / 2^n(对于无符号数)。

位运算在处理二进制数据时非常高效,能够直接对内存中的数据进行操作。

判断一个bit是否为1

要怎么样读取二进制的位数呢?
事实上,刚刚我们介绍的位运算符虽然能够对位进行操作,但是他们的对象依旧是基本数据类型。(A & B中,A、B都是基本数据类型)那到底要怎样实现遍历全部的bit呢?
答案是将bit的值用基本数据类型表示。

让我们看看下面这张图:
在这里插入图片描述
假如这张图代表一个二进制数据n,我们要做的事情是:

  • 如果最后一个bit的值为1,那么这个数据用十进制的int表示为1。
  • 反之,如果最后一个bit的值为0,那么这个数据用十进制的int表示为0.

十进制1和n的内存对比如下:
在这里插入图片描述
这时候,如果我们使用按位与(&)会怎么样?

没错!在这里插入图片描述
n&1的值为1!

那如果最后一位为0呢?这时候我们再使用一次按位与(&):
在这里插入图片描述
没错!是0!

使用按位与,我们可以实现判断最后一位是否为1

结合if,我们可以轻松实现这个判断:

if( n & 1 )

此时,我们实现了判断一个bit是否为1的程序。

遍历所有的bit

我们判断bit的条件是:这个bit是最后一位。
那么,我们只要每判断一次bit,我们把数据”往后移动一位“,就可以实现下一次判断的条件。

担当起这个任务的位运算符为: >>。

所谓右移运算符

右移运算符(>>)是一种位运算符,用于将一个数的二进制表示向右移动指定的位数。

  • 基本概念
    功能:将一个数的二进制位向右移动指定的位数,右边移出的位被丢弃,左边空出的位根据数的类型进行填充。
    语法:number >> n,其中number是要进行右移操作的数,n是要移动的位数。
  • 移动规则
    • 对于无符号数:左边空出的位用0填充。例如,对于无符号整数10(二进制为 1010),10 >> 1的结果是5(二进制为101),左边空出的一位用0填充。

    • 对于有符号数:左边空出的位用符号位(即最高位)填充,这种填充方式称为符号扩展。

      例如,对于有符号整数-10(假设其二进制补码表示为11110110),-10 >> 1的结果是-5(二进制补码为11111011),左边空出的一位用符号位1填充。

具体实现

此时,我们只需建立这样一个语句,就可以轻松实现“往后移动一位”。

a = (unsigned int)a >> 1;

其中,(unsigned int)是强制类型转换,是确保左边空出的一位用0填充。

循环跳出方式

跳出循环?当全部的1都被“舍弃”,那么不就变成0了吗?使用while即可。

while (a != 0){}

全代码

我们将上面取得的成果全部结合起来,便得到了以下内容:

#include<stdio.h>

int sta_1(int a);

int main() {

	int a = 0;
	scanf_s("%d", &a);

	printf("%d", sta_1(a));

	return 0;
}

int sta_1(int a) {

	int num = 0;
	while (a != 0) {
		if (a & 1) num++;
		a = (unsigned int)a >> 1;
	}
	return num;
}

以上,是该题的一般解法。
但是,不要小看我和题目的羁绊啊喂!

Brian Kernighan算法

Brian Kernighan算法专门计算二进制中1的个数的算法。

内容

int countBits(int n) {
    int count = 0;
    while (n != 0) {
        n &= n - 1;  // 将n中最右边的1及其右边的所有位都置为0
        count++;     // 计数器加1
    }
    return count;
}

基本思想

利用n & (n-1)操作来消除一个整数n的二进制表示中最右边的1。

具体步骤

初始化一个计数器count为0。

当n不等于0时,执行以下操作:
执行n &= n-1,将n中最右边的1及其右边的所有位都置为0。
将计数器count加1。

返回计数器count的值,即二进制表示中1的个数。

辅助理解

  • 对于循环退出条件:如果一个整数不为0,那么这个整数至少有一位是1。

  • 对于n-1:如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。

例子

对于整数n=7,其二进制表示为111:

  • 第一次循环:n=7 & 6=6,count=1,此时n的二进制表示为110;
  • 第二次循环:n=6 & 5=4,count=2,此时n的二进制表示为100;
  • 第三次循环:n=4 & 3=0,count=3,此时n变为0,循环结束。
    最终,count的值为3,即n的二进制表示中有3个1。

该算法的优势在于,它只需要执行与1的个数相等的循环次数,即执行次数等于二进制表示中1的个数,这使得该算法在时间复杂度上更加高效。

嘿嘿

今天的刷题分享就到这里~
通过这道题,我们深入探索了位运算的奥秘,从基础操作到高效算法。
希望这篇文章能让你在编程路上更进一步,在你下次遇到类似问题时,能轻松搞定。喜欢的话,别忘了点赞关注哦,我们下次再见!

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

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

相关文章

基于SpringCloud的广告系统设计与实现(一)

一、广告系统概论 广告系统中计费方式&#xff1a;CPM 千次广告展现收费/CPT 按时间段/CPC用户点击类广告收费。 Mysql&#xff1a;进行广告数据的存储&#xff0c;以及检索系统监听Mysql做增量索引 Kafka:实现各微服务之间的通信 比如地域维度&#xff0c;时间维度 二、微服务…

React Native的现状与未来:从发展到展望

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Python在多个Excel文件中找出缺失数据行数多的文件

本文介绍基于Python语言&#xff0c;针对一个文件夹下大量的Excel表格文件&#xff0c;基于其中每一个文件内、某一列数据的特征&#xff0c;对其加以筛选&#xff0c;并将符合要求与不符合要求的文件分别复制到另外两个新的文件夹中的方法。 首先&#xff0c;我们来明确一下本…

【JSqlParser】Java使用JSqlParser解析SQL语句总结

简述 Java解析SQL语句有很多工具都可以做到&#xff0c;比如Mybatis、Druid、目前用来用去最全面的仍然是Jsqlparser&#xff0c;它是一个Github上的开源项目&#xff0c;JSqlParser是一个用于解析SQL语句的Java库&#xff0c;它可以帮助开发者分析和操作SQL语句的结构。无论是…

WINFORM - DevExpress -> alertControl1提示信息框

第一个按钮为常规按钮, 单击触发 ButtonClick 事件. 第二个按钮有选中和未选中状态. 单击触发 ButtonDownChanged 事件。 if (e.ButtonName "alertButton2") { } 在dev用户界面中进行提示(usecontrolwinform) AlertInfo info new AlertInfo("提示",…

springboot全局异常处理示例

这种错误交给前端无法处理。 需要自定义一些错误响应类给前端 package cn.yam.bloomfilter.exception;import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.ht…

Windows远程桌面网关出现重大漏洞

微软披露了其Windows远程桌面网关&#xff08;RD Gateway&#xff09;中的一个重大漏洞&#xff0c;该漏洞可能允许攻击者利用竞争条件&#xff0c;导致拒绝服务&#xff08;DoS&#xff09;攻击。该漏洞被标识为CVE-2025-21225&#xff0c;已在2025年1月的补丁星期二更新中得到…

Shell正则表达式与文本处理三剑客(grep、sed、awk)

一、正则表达式 Shell正则表达式分为两种&#xff1a; 基础正则表达式&#xff1a;BRE&#xff08;basic regular express&#xff09; 扩展正则表达式&#xff1a;ERE&#xff08;extend regular express&#xff09;&#xff0c;扩展的表达式有、?、|和() 1.1 基本正则表…

基于 Spring Boot 和 Vue.js 的全栈购物平台开发实践

在现代 Web 开发中&#xff0c;前后端分离的架构已经成为主流。本文将分享如何使用 Spring Boot 和 Vue.js构建一个全栈购物平台&#xff0c;涵盖从后端 API 开发到前端页面实现的完整流程。 1. 技术栈介绍 后端技术栈 JDK 1.8&#xff1a;稳定且广泛使用的 Java 版本。 Spring…

Golang Gin系列-3:Gin Framework的项目结构

在Gin教程的第3篇&#xff0c;我们将讨论如何设置你的项目。这不仅仅是把文件扔得到处都是&#xff0c;而是要对所有东西的位置做出明智的选择。相信我&#xff0c;这些东西很重要。如果你做得对&#xff0c;你的项目会更容易处理。当你以后不再为了找东西或添加新功能而绞尽脑…

网络编程-UDP套接字

文章目录 UDP/TCP协议简介两种协议的联系与区别Socket是什么 UDP的SocketAPIDatagramSocketDatagramPacket 使用UDP模拟通信服务器端客户端测试 完整测试代码 UDP/TCP协议简介 两种协议的联系与区别 TCP和UDP其实是传输层的两个协议的内容, 差别非常大, 对于我们的Java来说, …

3.数据库系统

3.1数据库的基本概念 3.1.1:数据库体系结构 3.1.1.1集中式数据库系统 数据是集中的 数据管理是集中的 数据库系统的素有功能(从形式的用户接口到DBMS核心)都集中在DBMS所在的计算机 3.1.1.2C/S结构 客户端负责数据表示服务服务器主要负责数据库服务 数据库系统分为前端和后端…

探索 Transformer²:大语言模型自适应的新突破

目录 一、来源&#xff1a; 论文链接&#xff1a;https://arxiv.org/pdf/2501.06252 代码链接&#xff1a;SakanaAI/self-adaptive-llms 论文发布时间&#xff1a;2025年1月14日 二、论文概述&#xff1a; 图1 Transformer 概述 图2 训练及推理方法概述 图3 基于提示的…

【北京迅为】iTOP-4412全能版使用手册-第八十七章 安装Android Studio

iTOP-4412全能版采用四核Cortex-A9&#xff0c;主频为1.4GHz-1.6GHz&#xff0c;配备S5M8767 电源管理&#xff0c;集成USB HUB,选用高品质板对板连接器稳定可靠&#xff0c;大厂生产&#xff0c;做工精良。接口一应俱全&#xff0c;开发更简单,搭载全网通4G、支持WIFI、蓝牙、…

LDD3学习8--linux的设备模型(TODO)

在LDD3的十四章&#xff0c;是Linux设备模型&#xff0c;其中也有说到这个部分。 我的理解是自动在应用层也就是用户空间实现设备管理&#xff0c;处理内核的设备事件。 事件来自sysfs和/sbin/hotplug。在驱动中&#xff0c;只要是使用了新版的函数&#xff0c;相应的事件就会…

Jira中bug的流转流程

Jira中bug的状态 1. 处理Bug的流程2. bug状态流转详述bug的状态通常包括 1. 处理Bug的流程 2. bug状态流转详述 bug的状态通常包括 未解决 1. 测试人员创建一个bug&#xff0c;填写bug的详细信息&#xff0c;如概要、bug级别、复现步骤、现状、预期结果等 2. 定位bug&#x…

解决关于Xcode16提交审核报错

# 问题描述 The following issues occurred while distributing your application. Asset validation failed Invalid Executable. The executable xxx.app/Frameworks/HappyDNS.framework/HappyDNS contains bitcode.(lD:ef5dd249-731f-4731-8173-8e4a12519352) Asset valida…

windows下安装并使用node.js

一、下载Node.js 选择对应你系统的Node.js版本下载 Node.js官网下载地址 Node.js中文网下载地址??? 这里我选择的是Windows64位系统的Node.js20.18.0&#xff08;LTS长期支持版本&#xff09;版本的.msi安装包程序 官网下载&#xff1a; 中文网下载&#xff1a; 二、安…

基于SpringBoot+Vue旅游管理系统的设计和实现(源码+文档+部署讲解)

个人名片 &#x1f525; 源码获取 | 毕设定制| 商务合作&#xff1a;《个人名片》 ⛺️心若有所向往,何惧道阻且长 文章目录 个人名片环境需要技术栈功能介绍功能说明 环境需要 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 数据库&…

python之二维几何学习笔记

一、概要 资料来源《机械工程师Python编程&#xff1a;入门、实战与进阶》安琪儿索拉奥尔巴塞塔 2024年6月 点和向量&#xff1a;向量的缩放、范数、点乘、叉乘、旋转、平行、垂直、夹角直线和线段&#xff1a;线段中点、离线段最近的点、线段的交点、直线交点、线段的垂直平…