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

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

题目

统计二进制中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的个数,这使得该算法在时间复杂度上更加高效。

嘿嘿

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

音频语言模型与多模态体系结构

音频语言模型与多模态体系结构 多模态模型正在创造语言、视觉和语音等以前独立的研究领域的协同效应。这些模型使用通用架构,将每种模式视为不同的“token”,使它们能够以一种与人类认知非常相似的方式联合建模和理解世界。 ​ ​可以将多模态分为两个主要领域:输入空间(…

25/1/15 嵌入式笔记 初学STM32F108

GPIO初始化函数 GPIO_Ini&#xff1a;初始化GPIO引脚的模式&#xff0c;速度和引脚号 GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIOA的引脚0 GPIO输出控制函数 GPIO_SetBits&#xff1a;将指定的GPIO引脚设置为高电平 GPIO_SetBits(GPIOA, GPIO_Pin_0); // 将GPIO…

《机器学习》——SVD(奇异分解)降维

文章目录 SVD基本定义SVD降维的步骤SVD降维使用场景SVD 降维的优缺点SVD降维实例导入所需库定义SVD降维函数导入图像处理图像处理图像打印降维结果并显示处理后两个图像的对比图 SVD基本定义 简单来说就是&#xff0c;通过SVD&#xff08;奇异值分解&#xff09;对矩阵数据进行…

医疗集群系统中基于超融合数据库架构的应用与前景探析

一、引言 1.1 研究背景与意义 随着医疗信息化的飞速发展,医疗数据呈爆炸式增长。从日常诊疗记录、患者病历,到各类医疗影像、检查检验数据等,海量信息不断涌现。据统计,医疗数据的年增长率高达 30% 以上 ,2025 年,全球医疗数据量将达到 2314 艾字节(EB)。如此庞大的数…

闪豆多平台视频批量下载器

1. 视频链接获取与解析 首先&#xff0c;在哔哩哔哩网页中随意点击一个视频&#xff0c;比如你最近迷上了一个UP主的美食制作视频&#xff0c;想要下载下来慢慢学。点击视频后&#xff0c;复制视频页面的链接。复制完成后&#xff0c;不要急着关闭浏览器&#xff0c;因为接下来…

深度学习模块C2f代码详解

C2f 是一个用于构建卷积神经网络&#xff08;CNN&#xff09;的模块&#xff0c;特别是在 YOLOv5 和 YOLOv8 等目标检测模型中。这个模块是一个改进的 CSP&#xff08;Cross Stage Partial&#xff09;Bottleneck 结构&#xff0c;旨在提高计算效率和特征提取能力。下面是对 C2…

matlab展示龙格现象

为了展示龙格现象&#xff0c;它使用拉格朗日插值多项式&#xff0c;展示了随着插值点数目的增加&#xff0c;插值多项式在区间端点附近震荡的现象。 重新编写的 MATLAB 代码&#xff1a; % 定义目标函数 f (x) 1 ./ (1 x.^2);% 设置插值区间 x_interval [-5, 5]; % 插值…

浅谈云计算19 | OpenStack管理模块 (上)

OpenStack管理模块&#xff08;上&#xff09; 一、操作界面管理架构二、认证管理2.1 定义与作用2.2 认证原理与流程2.2.1 认证机制原理2.2.2 用户认证流程 三、镜像管理3.1 定义与功能3.2 镜像服务架构3.3 工作原理与流程3.3.1 镜像存储原理3.3.2 镜像检索流程 四、计算管理4.…

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

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

SpringBoot3-整合WebSocket指南

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞??收藏评论 SpringBoot3-整合WebSocket指南 1. 什么是WebSocket?2. 环境准备 2.1 项目依赖 3. WebSocket配置 3.1 WebSocket配置类3.2 自定义WebSocket处理器 4. 控制器5. 前端实现 5.1 HTML页面…

技术晋升读书笔记—办事的艺术

作为一名程序员&#xff0c;沟通能力对于我们这一行来说并不是强项。大多数程序员与电脑打交道的时间远远多于与人交流&#xff0c;特别工作一天有可能全程在与电脑打交道&#xff0c;因此沟通技巧的提升往往被忽视。然而&#xff0c;随着职业发展的推进&#xff0c;尤其在国内…

警惕IDEA 2024版重大Bug问题:LomBok失效、Gradle冲突、Spring Boot启动错误

一直以来我认为工具类的软件是越新越好&#xff0c;因为工具代表着一定的先进性&#xff1b;但是IDEA 2024好好的给我上了一课&#xff0c;比如lombok 不起作用、比如Spring Boot 3.4.x 启动报错、再比如MyBatis log plus冲突、再比如Gradle插件冲突. 一、Lombok 失效问题 请不…

01、flink的原理和安装部署

flink中主要有两个进程&#xff0c;分别是JobMManager和TaskManager&#xff0c;当然了根据flink的部署和运行环境不同&#xff0c;会有一些不同&#xff0c;但是主要的功能是类似的&#xff0c;下面我会讲下聊下&#xff0c;公司用的多的部署方式&#xff0c;基于yarn集群的部…

Vue2+OpenLayers实现车辆开始、暂停、重置行驶轨迹动画(提供Gitee源码)

前言&#xff1a;根据经纬度信息绘制一个完整的行驶路线&#xff0c;车辆根据绘制好的路线从开始点位行驶到结束点位&#xff0c;可以通过开始、暂停、重置按钮控制车辆状态。 目录 一、案例截图 二、安装OpenLayers库 三、​安装Element-UI ​ 四、代码实现 4.1、初始化…

两个React项目部署在同一个域名,一个主地址,一个子地址,二级白屏等问题

主域名配置的那个项目正常配置就可以了&#xff0c;但是对于子地址的项目&#xff0c;需要做很多的配置的。 注意 子地址的那个项目在配置中需要配置为子地址&#xff1a; base: /subpk 在vite.config.ts中修改&#xff1a; 如果这里没有配置正确&#xff0c;会导致白屏或者…

管理口令安全和资源(二)

DBMS_METADATA DBMS_METADATA 是 Oracle 数据库中的一个包&#xff0c;它提供了用于管理数据库元数据的工具和过程。元数据是关于数据的数据&#xff0c;它描述了数据库的结构&#xff0c;包括表、视图、索引、存储过程、用户和其他数据库对象的信息。DBMS_METADATA 包允许用户…

【狂热算法篇】探秘图论之 Floyd 算法:解锁最短路径的神秘密码(通俗易懂版)

&#xff1a; 羑悻的小杀马特.-CSDN博客羑悻的小杀马特.擅长C/C题海汇总,AI学习,c的不归之路,等方面的知识,羑悻的小杀马特.关注算法,c,c语言,青少年编程领域.https://blog.csdn.net/2401_82648291?spm1010.2135.3001.5343 在本篇文章中&#xff0c;博主将带大家去学习所谓的…

Kotlin Bytedeco OpenCV 图像图像57 图像ROI

Kotlin Bytedeco OpenCV 图像图像57 图像ROI 1 添加依赖2 测试代码3 测试结果 1 添加依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns"http://maven.apache.o…

Linux手写FrameBuffer任意引脚驱动spi屏幕

一、硬件设备 开发板&#xff1a;香橙派 5Plus&#xff0c;cpu&#xff1a;RK3588&#xff0c;带有 40pin 外接引脚。 屏幕&#xff1a;SPI 协议 0.96 寸 OLED。 二、需求 主要是想给板子增加一个可视化的监视器&#xff0c;并且主页面可调。 平时跑个模型或者服务&#xff0c;…

【Linux】gdb_进程概念

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…