当前位置: 首页 > news >正文

位运算 常见方法总结 算法练习 C++

文章目录

  • 1. 基础位运算
    • 左移运算符 `<<`
    • 右移运算符 `>>`
    • 按位与 `&`
    • 按位或 `|`
    • 按位异或 `^`
  • 2. 位运算的优先级
  • 3. 给你一个数n确定其的二进制表示中的第x位是0还是1
  • 4. 将一个数n的二进制表示的第x位修改成1
  • 5. 将一个数n的二进制表示的第x位修改成0
  • 6. 位图的思想
  • 7. 提取一个数n的二进制表示中的最右侧的1 (lowbit)
  • 8. 清除一个数n二进制表示中的最右侧的1
  • 9. 异或(^)操作的运算律
  • 相关题目练习
  • 常见误区总结

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

注:二进制中我们规定右边是最低位,从右向左记下标为0,1,2,3…

int n =  0 0 1 0 1 1 1 0 1...8 7 6 5 4 3 2 1 0  (下标,因为是int所以32位)

至于为什么要以下标为0开始?
下标从0开始的设计与右移操作相匹配:若要将下标为2的位移动到最低位,只需右移2位即可,操作数与下标完全对应,非常直观。

1. 基础位运算

左移运算符 <<

功能:将一个数的二进制位向左移动指定的位数,右侧空出的位用0填充。

int a = 5;       // 二进制: 00000101
int b = a << 2;  // 二进制: 00010100,结果为20

移动过程

    00000101  (5)   // 原始值
<<  2               // 左移2位
----------------00010100  (20)  // 结果值

说明:左移n位相当于在不溢出的情况下乘以2ⁿ,运算效率远高于乘法。
⚠️ 常见误区:若左移导致有符号数的符号位发生变化(如int类型的0b10000000左移1位),会触发溢出,结果不再符合“乘2ⁿ”规则,实际开发中需注意数值范围。

右移运算符 >>

功能:将一个数的二进制位向右移动指定的位数。

  • 无符号整数:左侧空出的位用0填充
  • 有符号整数:通常采用算术右移,左侧空出的位用符号位填充
int a = 10;      // 二进制: 00001010
int b = a >> 2;  // 二进制: 00000010,结果为2

移动过程

    00001010  (10)  // 原始值
>>  2               // 右移2位
----------------00000010  (2)   // 结果值

说明:右移n位相当于在不考虑符号的情况下除以2ⁿ(向下取整)。

按位与 &

运算规则:两个数的对应二进制位都为1时,结果位才为1(有0则0,全1才1)。

int a = 5;       // 二进制: 00000101
int b = 3;       // 二进制: 00000011
int c = a & b;   // 二进制: 00000001,结果为1

运算过程

    00000101  (5)
&   00000011  (3)
----------------00000001  (1)

说明:只有两个对应位同时为1,结果才为1,可用于筛选特定位。

按位或 |

运算规则:两个数的对应二进制位中只要有一个为1,结果位就为1(有1则1,全0才0)。

int a = 5;       // 二进制: 00000101
int b = 3;       // 二进制: 00000011
int c = a | b;   // 二进制: 00000111,结果为7

运算过程:

    00000101  (5)
|   00000011  (3)
----------------00000111  (7)

说明:只要有一个对应位为1,结果就为1,可用于设置特定位。

按位异或 ^

运算规则:两个数的对应二进制位不同时,结果位为1;相同时,结果位为0。

int a = 5;       // 二进制: 00000101
int b = 3;       // 二进制: 00000011
int c = a ^ b;   // 二进制: 00000110,结果为6

运算过程:

    00000101  (5)
^   00000011  (3)
----------------00000110  (6)

说明:异或可理解为"无进位相加",相同为0,不同为1,后续会介绍其重要运算律及实战应用。

2. 位运算的优先级

位运算符的优先级从高到低排列如下:

  1. 按位非 ~(单目运算符,优先级最高)
  2. 左移 <<、右移 >>
  3. 按位与 &
  4. 按位异或 ^
  5. 按位或 |

与其他运算符的关系

  • 位运算符优先级低于算术运算符(+-*/)和关系运算符(><==
  • 位运算符优先级高于逻辑运算符(&&||

实用建议
位运算符的优先级关系复杂,记忆困难。实际编程中,建议使用括号明确指定运算顺序,既避免错误又提高可读性:

int result = (a | b) & (c << 2);  // 清晰的运算顺序

3. 给你一个数n确定其的二进制表示中的第x位是0还是1

方法(n >> x) & 1

步骤解析

  1. 右移定位:将n右移x位,使第x位移到最低位(第0位),此时其他位均被移走或填充(不影响最低位);
  2. 按位筛选:与1(二进制0b...0001)按位与,保留最低位(原第x位),清除其他所有位;
  3. 结果判断:最终结果为0 → 原第x位是0;结果为1 → 原第x位是1。

示例:判断n=5(101)的第2位:
在这里插入图片描述

4. 将一个数n的二进制表示的第x位修改成1

方法n = n | (1 << x)

步骤解析

  1. 将1左移x位,得到一个只有第x位为1、其余位为0的数(掩码)
  2. 与n进行按位或运算,使n的第x位变为1,其他位保持不变

示例:将n=5(101)的第1位改为1:
在这里插入图片描述

5. 将一个数n的二进制表示的第x位修改成0

方法n = n & (~(1 << x))

步骤解析

  1. 将1左移x位,得到只有第x位为1的数
  2. 对其取反,得到只有第x位为0、其余位为1的数(掩码)
  3. 与n进行按位与运算,使n的第x位变为0,其他位保持不变

示例:将n=5(101)的第2位改为0:
在这里插入图片描述

6. 位图的思想

我们上面说的几点都是为这一点也就是位图服务的👇
位图的本质就是一个哈希表(数组),不同的是哈希表是将数据存储到数组中方便我们来查找,而位图是用一个变量,其中每个二进制位来记录我们的信息,0/1表示不同信息,所以说用位图来记录我们就会经常用到上面的几个操作。
在这里插入图片描述

官方一点就是👇
位图(BitMap)是位运算的重要应用,其本质是用一个二进制位来表示一个数据的状态(0或1),从而极大节省存储空间。

核心思想

  • 传统哈希表用一个元素存储一个数据
  • 位图用一个二进制位标记一个数据的存在状态
  • 一个32位整数可以表示32个数据的状态

优势

  • 空间效率极高(存储相同数据量,仅需传统方法的1/32空间)
  • 操作高效(基于位运算,速度快)

应用场景

  • 海量数据去重
  • 数据查找与判重
  • 标记状态集合

实现基础
位图的实现依赖于前面介绍的位操作:

  • 判断某数据是否存在 → 使用"判断第x位是0还是1"
  • 添加数据 → 使用"将第x位修改为1"
  • 删除数据 → 使用"将第x位修改为0"

7. 提取一个数n的二进制表示中的最右侧的1 (lowbit)

方法n & (-n)

计算机中负数以补码存储,补码规则为:

  1. 正数的补码 = 其原码(二进制本身);
  2. 负数的补码 = 对其绝对值的原码“取反(~)”后加1(即 -n = ~n + 1)。

lowbit的核心逻辑:对n取负后,最右侧的1保持不变,其左侧所有位取反,与原数按位与后,仅保留最右侧的1。

原理:在补码表示中,-n = ~n + 1,会使最右侧的1保持不变,其左侧所有位取反,我们理解了 -n 的含义这个方法就很好理解了。
在这里插入图片描述
当我们进行 -n 操作之后,最右侧的1右边部分没有动,左边的部分全部取反,那么我们与原来的数 & ,我们发现右边的部分因为取反全为0,左边的部分没动但都是0。

示例:提取424的二进制表示中的最右侧的1
在这里插入图片描述

8. 清除一个数n二进制表示中的最右侧的1

方法n & (n - 1)

原理:当对 n 减 1 时,会触发“借位”逻辑——从最右侧的 1 开始,该位变为 0,其右侧所有的 0 均变为 1;此时与原数 n 按位与,最右侧的 1 会被“抵消”为 0,其他位保持不变,最终实现“清除最右侧 1”的效果
在这里插入图片描述

示例:清除n=106(110101000)最右侧的1:
在这里插入图片描述

9. 异或(^)操作的运算律

异或运算具有以下重要性质,在算法设计中非常实用:

(1) 恒等律a ^ 0 = a
任何数与0异或,结果仍为该数

(2) 归零律a ^ a = 0
任何数与自身异或,结果为0

(3) 结合律a ^ b ^ c = a ^ (b ^ c)
异或运算的顺序不影响最终结果

(4) 自反性a ^ b ^ b = a
连续两次与同一个数异或,结果为原数

应用示例:不使用临时变量交换两个数

int x = 10, y = 20;
x = x ^ y;  // x现在是x^y
y = x ^ y;  // y = (x^y)^y = x
x = x ^ y;  // x = (x^y)^x = y

相关题目练习

以下题目需结合前文知识点实现,避免使用 C++ 内置函数(如 __builtin_popcount),强化对位运算逻辑的理解:

题目链接核心知识点解题思路提示
力扣 191. 位1的个数清除最右侧1(n & (n-1)循环执行 n = n & (n-1),每执行一次代表清除一个 1,计数加 1,直到 n 变为 0,最终计数即为 1 的个数。
力扣 338. 比特位计数清除最右侧1 / 动态规划方法1:对每个数循环清除最右侧 1 计数(基础思路);方法2:动态规划,dp[i] = dp[i & (i-1)] + 1(利用“i 比 i&(i-1) 多一个 1”的规律,优化效率)。
力扣 461. 汉明距离异或 + 位1计数步骤1:对两个数异或(x ^ y),异或结果中“1 的位置”即为两数二进制不同的位置;步骤2:统计异或结果中 1 的个数,即为汉明距离。
力扣 136. 只出现一次的数字异或运算律(归零律 + 恒等律)所有数异或:出现两次的数会因 a^a=0 抵消,最终结果即为“只出现一次的数”(0 ^ 唯一数 = 唯一数)。
力扣 260. 只出现一次的数字 IIIlowbit + 异或分组步骤1:所有数异或,结果为“两个唯一数的异或值(x^y)”;步骤2:用 lowbit 提取 x^y 最右侧的 1,以此为依据将数组分为两组(该位为 1 的组、为 0 的组),x 和 y 会分属不同组;步骤3:两组分别异或,得到两个唯一数。

常见误区总结

  1. 左移溢出风险:认为“左移 n 位一定等于乘 2ⁿ”,忽略有符号数的溢出问题(如 int 类型 0x80000000 左移 1 位,符号位从 1 变为 0,结果错误),实际使用需确保左移后数值在类型范围内。
  2. 右移符号位混淆:对负数右移的“补 1”规则不清晰,导致计算结果偏差(如 -10 >> 2 = -3,而非 -2,需记住“右移向下取整”)。
  3. 位图位位置计算:用 x % 32 计算位图中的位位置,效率低于 x & 31(位运算无需除法操作),且仅当“每个元素占 2^k 位”时可用(如 64 位元素用 x & 63)。
  4. 异或交换的局限:无临时变量交换仅适用于“两个不同的变量”,若 x 和 y 指向同一内存地址(如 swap(x, x)),会导致 x 变为 0(x = x^x = 0),实际开发需注意变量地址是否相同。
http://www.dtcms.com/a/398656.html

相关文章:

  • 电子商务平台网站源码国外炫网站
  • PTZ相机的知识体系
  • Nginx反向代理配置全流程实战:从环境搭建到HTTPS部署
  • HTTPS 能抓包吗?实战答案与逐步可行方案(HTTPS 抓包原理、证书Pinning双向认证应对、工具对比)
  • 对网站建设的讲话wordpress 自定义面板
  • 【23】C++实战篇——C++报错:LNK2001:无法解析的外部符号 ,LNK2019: 无法解析的外部符号,原因分析及解决方法
  • 东莞建设银行官方网站礼品网站制作
  • TiDB Cloud 可观测性最佳实践
  • python+springboot毕业季旅游一站式定制服务系统
  • docker 启用容器端口被占用报错500
  • 无人机台风天通信技术要点
  • ParaZero-无人机降落伞领先开发商:SafeAir降落伞系统、DropAir精确空投系统、DefendAir反无人机系统
  • 手机怎样创建网站网站内容保护
  • 电路基础与PCB设计(一)电路
  • YOLO入门教程(四):搭建YOLOv1网络
  • k8s中的Gateway API 和istio
  • K8S (使用步骤)
  • k8s 跟 nacos 关于服务注册以及服务发现
  • 专业的家居网站建设深圳高端网站建设公司
  • Ubuntu vscode软件的安装和使用
  • [Maven 基础课程]10_Maven 私服
  • Python11-集成学习
  • 代做网站灰色关键词青州网站搭建
  • Spring-MVC响应
  • 正确看待和使用TDD测试驱动开发
  • 红外热成像与数字图像相关(DIC)技术耦合在金属热变形分析中的应用
  • 做拍卖网站有哪些教做宝宝辅食的网站
  • 第一章:Go语言的起源-云原生时代的C位语言​​
  • Auto_CVE - 自动化漏洞挖掘系统
  • python+springboot+vue的旅游门票信息系统web