个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创位运算(1)_常见位运算总结
收录于专栏【经典算法练习】
本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌
目录
1. 基础位运算
位运算的基本概念:
位运算的应用:
2. 给一个数n,确定它的二进制表示中的第x位是0还是1
3. 将一个数n的二进制表示的第x位修改成1
4. 将一个数n的二进制表示的第x位修改成0
5. 位图的思想
1. 位图的基本概念
2. 位图的构建
3. 基本操作
4. 位图的优点
5. 位图的应用
6. 提取一个数(n)二进制表示中最右侧的1
7. 除去一个数(n)二进制表示中最右侧的1
8. 位运算的优先级
9. 异或(^)运算的运算律
1. 基础位运算
运算符 | 描述 | 示例 |
---|---|---|
& | 按位与 | a & b |
| | 按位或 | a | b |
^ | 按位异或 | a ^ b |
~ | 按位取反 | a ~ b |
<< | 左移 | a << n |
>> | 右移 | a >> n |
位运算的基本概念:
按位与(AND)(&):
只有对应位都为1时,结果为1。
示例:5 & 3(0101 & 0011 = 0001)结果为 1。
按位或( | ):
对应位有一个为1时,结果为1;只有当对应位都是0时,结果才为0。
示例:5 | 3:(0101 | 0011 = 0111) (结果为7)
按位异或(XOR)(^):
对应位不同(一个为1,一个为0)时结果为1。
示例:5 ^ 3(0101 ^ 0011 = 0110)结果为 6。
按位取反(NOT)(~):
将每一位取反(0变1,1变0)。
示例:~5(~0101 = 1010,在补码表示中会得到 - 6)。
左移( << ):
将所有位向左移动n位,右侧补0。相当于乘以2的n次方。
示例:5 << 1(0101 << 1 = 1010)结果为 10。
右移( >> ):
将所有位向右移动n位,左侧补符号位(对于负数,补1;对于正数,补0)。
示例:5 >> 1(0101 >> 1 = 0010)结果为 2。
位运算的应用:
位运算在许多情况下非常有用,常见的应用包括:
快速计算:
位运算可以用于快速计算乘法和除法(通过左移和右移)。
状态存储:
使用位运算可以在单个整数中存储多个布尔值,节省空间。
位掩码(Bitmasking):
通过位运算可以方便地操作集合,例如加入、删除和检查元素。
查找特定位:
检查某一位是否为1,例如 a& (1 << n) 检查整数 a 的第 n 位。
2. 给一个数n,确定它的二进制表示中的第x位是0还是1
方法: (n >> x) & 1
示例:
3. 将一个数n的二进制表示的第x位修改成1
方法: n = n | (1 << x)
示例:
4. 将一个数n的二进制表示的第x位修改成0
方法: n = n & (~(1 << x))
示例:
5. 位图的思想
位图(Bitmap)是一种高效的数据结构,用于表示集合或管理数据的存在性。它通过位的方式存储信息,能够在空间和时间上进行优化,特别是在处理大范围的数据时。
1. 位图的基本概念
位图使用一个二进制数组(比特数组)来表示元素的存在性。每一个比特(0或1)对应集合中的一个元素:
如果某个比特为 1,表示集合中存在对应的元素。
如果某个比特为 0,表示集合中不存在对应的元素。
例如,假设我们有一个范围为 0 到 9 的整数集合,可以使用一个大小为 10 的位图:
0 代表数字 0 的存在
1 代表数字 1 的存在
2. 位图的构建
假设我们要管理一组整数,位图的构建步骤如下:
初始化一个数组,大小为最大元素值加一(或按需要的范围进行调整)。
对于每一个要添加到集合中的元素,将对应位设为 1。
3. 基本操作
插入元素:
对于一个元素x,将位图的第x 位设为 1。
示例:bitmap[x] = 1;
删除元素:
对于一个元素x,将位图的第x 位设为 0。
示例:bitmap[x] = 0;
查询元素:
对于一个元素x,检查位图的第x 位是否为 1。
示例:if(bitmap[x] == 1) { /* 存在 */ }
4. 位图的优点
空间效率:相比于存储完整的数据结构,位图可以大大减少存储空间,特别是在处理大范围的整数时。
快速操作:位图的插入、删除和查询操作时间复杂度为O(1),非常高效。
缓存友好:由于位图在内存中是连续的,可以更好地利用缓存。
5. 位图的应用
集合操作:用于实现集合的并、交、差等操作。
去重:快速检测数据中是否存在重复元素。
压缩存储:在一些场景中,结合其他压缩技术,可以显著减少内存使用。
图像处理:用作图像的像素表示,尤其是黑白图像。
操作系统:在内存管理中,位图常用于表示空闲和占用的内存块。
6. 提取一个数(n)二进制表示中最右侧的1
方法: n & (-n)
示例:
7. 除去一个数(n)二进制表示中最右侧的1
方法: n & (n - 1)
示例:
8. 位运算的优先级
1. 按位取反(~)
2. 位移运算(左移 << 和 右移 >> )
3. 按位与( & )
4. 按位异或( ^ )
5. 按位或( | )
int a = 5; // 二进制: 0000 0101
int b = 3; // 二进制: 0000 0011
int result = a & b | b ^ a << 1;
左移运算:a << 1 先计算,结果是 10(即 0000 1010)。
按位异或:b ^ a 计算,结果是 6(即 0000 0110)。
按位与:a & b 计算,结果是 1(即 0000 0001)。
按位或:最后,1 | 6 计算,结果是 7(即 0000 0111)。
注意: 如果对位运算的优先级不是很了解的话,括号能加尽加
9. 异或(^)运算的运算律
1. 交换律
异或运算具有交换性,即对于任意两个数
a和b,有:a^b = b^a
这意味着在进行异或运算时,操作数的顺序可以互换。
2. 结合律
异或运算也具有结合性,即对于任意三个数
a、b 和c,有:(a^b)^c = a^(b^c)
这意味着在进行多个异或运算时,可以自由地重新组合操作数。
3. 身份律
异或运算有身份元素,即对于任意数
a,有:a^0 = a
这表明将任意数与0进行异或运算的结果仍然是该数本身。
4. 自反律
对于任意数a,有:a^a = 0
这意味着一个数与自身进行异或运算的结果是0。
5. 与1的运算
对于任意数a,有:a^1 = ∼a
这表示将一个数与1进行异或运算相当于对该数进行按位取反。
6. 传播性
异或运算满足传播性(或称为分配性),即对于任意数
a、b 和c,有:a^(b^c) = (a^b)^c
这说明无论如何组合多个异或操作,结果都是一致的。