位运算(超详细篇)

  ✅博客主页:爆打维c-优快云博客​​​​​​ 🐾

🔹分享c、c++知识及代码 🐾


一、基本位运算操作符详解

在C++中,位运算(bitwise operations)是对整数的二进制表示进行直接操作的一种运算方式。这些操作通常比标准的算术运算更快,因为它们直接在底层硬件上执行。C++中的位运算主要包括以下几种:

  1. 按位与
    • 符号:&
    • 操作:对两个整数的每一位进行逻辑与操作。如果两个相应位都为1,则该位结果为1,否则为0。
    • 示例:5 & 3 => 0101 & 0011 => 0001 => 1
  2. 按位或
    • 符号:|
    • 操作:对两个整数的每一位进行逻辑或操作。如果两个相应位中至少有一个为1,则该位结果为1,否则为0。
    • 示例:5 | 3 => 0101 | 0011 => 0111 => 7
  3. 按位异或
    • 符号:^
    • 操作:对两个整数的每一位进行逻辑异或操作。如果两个相应位不同,则该位结果为1,否则为0。
    • 示例:5 ^ 3 => 0101 ^ 0011 => 0110 => 6
  4. 按位取反
    • 符号:~
    • 操作:对一个整数的每一位进行逻辑非操作。将1变为0,0变为1。
    • 示例:~5 => ~0101 => 1010(注意:在补码表示法中,这是-6的二进制表示,前提是整数是8位的)
  5. 左移
    • 符号:<<
    • 操作:将一个整数的二进制表示向左移动指定的位数,右边用0填充。
    • 示例:5 << 2 => 0101 << 2 => 10100 => 20
  6. 右移
    • 符号:>>
    • 操作:将一个整数的二进制表示向右移动指定的位数,对于无符号整数,左边用0填充;对于有符号整数,左边用符号位(即最左边的位)填充(这称为算术右移)。
    • 示例:5 >> 2 => 0101 >> 2 => 0001 => 1(算术右移)
    • 补充: 在逻辑右移中,所有位都向右移动,不考虑符号位。
  7. 复合赋值运算符
    • 这些运算符将位运算的结果赋值给变量,例如&=|=^=<<=>>=
    • 示例: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)

268. 丢失的数字 - 力扣(LeetCode)

面试题 17.19. 消失的两个数字 - 力扣(LeetCode)


如果这篇文章对你有帮助的话,请给博主一个免费的赞鼓励一下吧~ 💓

本文仅简单介绍了有关位运算操作的一些基本概念和相关代码实现,以上个人拙见,若有错误之处,希望各位能提出宝贵的建议和更正,感谢您的观看!

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值