✅博客主页:爆打维c-优快云博客 🐾
🔹分享c、c++知识及代码 🐾
一、基本位运算操作符详解
在C++中,位运算(bitwise operations)是对整数的二进制表示进行直接操作的一种运算方式。这些操作通常比标准的算术运算更快,因为它们直接在底层硬件上执行。C++中的位运算主要包括以下几种:
- 按位与:
- 符号:
&
- 操作:对两个整数的每一位进行逻辑与操作。如果两个相应位都为1,则该位结果为1,否则为0。
- 示例:
5 & 3
=>0101 & 0011
=>0001
=>1
- 符号:
- 按位或:
- 符号:
|
- 操作:对两个整数的每一位进行逻辑或操作。如果两个相应位中至少有一个为1,则该位结果为1,否则为0。
- 示例:
5 | 3
=>0101 | 0011
=>0111
=>7
- 符号:
- 按位异或:
- 符号:^
- 操作:对两个整数的每一位进行逻辑异或操作。如果两个相应位不同,则该位结果为1,否则为0。
- 示例:
5 ^ 3
=>0101 ^ 0011
=>0110
=>6
- 按位取反:
- 符号:~
- 操作:对一个整数的每一位进行逻辑非操作。将1变为0,0变为1。
- 示例:
~5
=>~0101
=>1010
(注意:在补码表示法中,这是-6的二进制表示,前提是整数是8位的)
- 左移:
- 符号:
<<
- 操作:将一个整数的二进制表示向左移动指定的位数,右边用0填充。
- 示例:
5 << 2
=>0101 << 2
=>10100
=>20
- 符号:
- 右移:
- 符号:
>>
- 操作:将一个整数的二进制表示向右移动指定的位数,对于无符号整数,左边用0填充;对于有符号整数,左边用符号位(即最左边的位)填充(这称为算术右移)。
- 示例:
5 >> 2
=>0101 >> 2
=>0001
=>1
(算术右移) - 补充: 在逻辑右移中,所有位都向右移动,不考虑符号位。
- 符号:
- 复合赋值运算符:
- 这些运算符将位运算的结果赋值给变量,例如
&=
,|=
,^=
,<<=
,>>=
。 - 示例:
a &= b
等价于a = a & b
。
- 这些运算符将位运算的结果赋值给变量,例如
示例代码
#include <iostream>
using namespace std;
int main() {
int a = 5; // 0101
int b = 3; // 0011
cout << "a & b = " << (a & b) << endl; // 0001 => 1
cout << "a | b = " << (a | b) << endl; // 0111 => 7
cout << "a ^ b = " << (a ^ b) << endl; // 0110 => 6
cout << "~a = " << (~a) << endl; //~0101 => 1010 => -6 二进制补码形式表示
cout << "a << 2 = " << (a << 2) << endl; // 10100 => 20
cout << "a >> 2 = " << (a >> 2) << endl; // 0001 => 1
return 0;
}
二、位运算相关知识点
了解了上面位运算的基础知识,你是否知道如何修改一个数的第 x 位的二进制位呢?比如说如何将第 x 位修改为 1 ,或是修改为 0 。我们怎么能找到一个数的二进制表示中最右侧的 1 呢?...下面我将给出一些位运算相关知识点的总结!赶快拿出小本本记好!
- & 有0则为0
- | 有1则为1
- ^ 相同为1 不同为0 /无进位相加
总结1. 一个数n,确定它的二进制表示中的第 x 位是 0 还是 1
只需将n右移x位然后与1按位与,如果等于1则此位为1,等于0则此位为0
(n>>x)&1;
总结2. 将一个数n 的二进制表示的第 x 位修改成 1
由于按位或的特性是有1则1,只需将n与 1左移x位按位或 则可将此位改为1
n|=1<<x; //n=n|(1<<x)
总结3. 将一个数n 的二进制表示的第 x 位修改成 0
由于按位与的特性是有0则0,只需将n与 1左移x位后取反的结果 按位与 则可将此位改为0
n&=~(1<<X); //n=n&(~(1<<X))
总结4. 提取一个数(n)二进制表示中最右侧的1
找为1的最低比特位,只需第x位满足 (n>>x)&1==1 ,提取一个数(n)二进制表示中最右侧的1,只需用n&(~n)+1,下面我们给出示例
n=3 //0011
(~n)+1 //1101
//按位取反就是先将一个数写成其二进制表达形式,然后1变0,0变1
//本质是将最右侧1,左边区域二进制位都变相反
n&(~n)+1 //(0011)&(1101) ->0001 得到最右侧1
总结5. 去除一个数(n)二进制表示中最右侧的1
去除一个数(n)二进制表示中最右侧的1,只需用n&(n-1),下面我们给出示例
n=6 //0110
n-1 //0101
//本质是将最右侧1,右边区域(含自身)全变成相反
n=n&(n-1) //0100
总结6. 异或(^)运算的运算律
按位或的特性是 相同为1 不同为0,那么我们就有
- a^0=a
- a^a=0
另外按位异或也是符合交换律的 (a^b)^c=(a^c)^b 结果都相同
我们可以利用异或的特性,解出下面这道题 136. 只出现一次的数字 - 力扣(LeetCode)题目如下
只有一个元素出现一次, 其他元素均出现两次,那么利用上述结论 a^0=a ,a^a=0 ,将它们全都异或起来,可以轻松的得到答案!
实现代码
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret=0;
for(auto e:nums){
ret^=e;
}
return ret;
}
};
另外还有些题目,大家可以自行思考,方法在上面的知识点已经讲述完毕,希望大家看完这篇博客后能对基本的位运算操作融会贯通!
137. 只出现一次的数字 II - 力扣(LeetCode)
260. 只出现一次的数字 III - 力扣(LeetCode)
面试题 17.19. 消失的两个数字 - 力扣(LeetCode)
如果这篇文章对你有帮助的话,请给博主一个免费的赞鼓励一下吧~ 💓
本文仅简单介绍了有关位运算操作的一些基本概念和相关代码实现,以上个人拙见,若有错误之处,希望各位能提出宝贵的建议和更正,感谢您的观看!