杨校老师课堂之C++的位运算应用专项训练

位运算应用

2.2.1 与应用

规则:两个位都是1时结果为1,否则为0

C++ 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5;    // 二进制: 0101
    int b = 3;    // 二进制: 0011
    
    int res = a & b;  // 0101 & 0011 = 0001
    
    printf("a & b = %d\n",res);
    // 输出: 5 & 3 = 1
    
    return 0;
}

应用:检查奇偶性、掩码操作

C++ 复制代码
#include <iostream>
using namespace std;

int main() {
    int x = 13; // 二进制:...00001101
    
    if (x & 1) {
        // 如果 x & 1 的结果非零(即为1),条件为真
        cout << x << " 是奇数。" << endl;
    } else {
        cout << x << " 是偶数。" << endl;
    }
    
    // 运算过程:
    //       ...00001101  (x = 13)
    //     & ...00000001  (1)
    //     -----------
    //       ...00000001  (结果为 1,条件为真)
    
    return 0;
}

2.2.2 或应用

规则:两个位有一个是1时结果为1

C++ 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5;    // 二进制: 0101
    int b = 3;    // 二进制: 0011
    
    int res = a | b;  // 0101 | 0011 = 0111
    
    printf("a | b = %d\n",res);
    // 输出: 5 | 3 = 7
    
    return 0;
}

2.2.3 异或****应用

规则:两个位不同时结果为1

C++ 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5;    // 二进制: 0101
    int b = 3;    // 二进制: 0011
    
    int res = a ^ b;  // 0101 ^ 0011 = 0110
    
    printf("a ^ b = %d\n",res);
    // 输出: 5 ^ 3 = 6
    
    return 0;
}

① 简单的加密操作

原理: 异或有一个神奇的性质:

  • 如果 A ^ B = C
  • 那么 C ^ B = A

就像一个有两个相同钥匙的锁!

C++ 复制代码
 #include <iostream>
using namespace std;

int main() {
    string m = "Hello";  // 原始信息
    char key = 'K';            // 密钥
    
    cout << "原始信息: " << m << endl;
    
    // 加密:每个字符与密钥异或
    for (int i = 0; m[i] != '\0'; i++) {
        m[i] = m[i] ^ key;
    }
    cout << "加密后: " << m << endl;
    
    // 解密:再次与同一个密钥异或
    for (int i = 0; m[i] != '\0'; i++) {
        m[i] = m[i] ^ key;
    }
    cout << "解密后: " << m << endl;
    
    return 0;
}

② 交换变量(不需临时变量)

  • 先把两杯果汁倒在一起混合(a ^ b)
  • 从混合果汁中倒回一杯,得到原来的颜色(b = a ^ b)
  • 再从剩下的混合果汁中倒回另一杯,得到另一种颜色(a = a ^ b)
C++ 复制代码
#include <iostream>
using namespace std;

int main() {
    int a = 5, b = 3;
    
    cout << "交换前: a = " << a << ", b = " << b << endl;
    
    // 异或交换三连
    a = a ^ b;  // 步骤1:把a和b的信息"混合"
    b = a ^ b;  // 步骤2:从混合信息中提取原始a,存入b
    a = a ^ b;  // 步骤3:从混合信息中提取原始b,存入a
    
    cout << "交换后: a = " << a << ", b = " << b << endl;
    
    return 0;
}
/*
    交换前: a = 5, b = 3
    交换后: a = 3, b = 5
*/

2.2.4 取反应用

规则:所有位取反(0变1,1变0)

  • 取反后的二进制以「1」开头(符号位为 1),说明是负数

  • 要得到负数的十进制值,需通过补码反推原码:

    • 补码 → 原码的规则:负数的原码 = 补码的反码 + 1(符号位始终为 1)。

      • 二进制: 0000 0000 0000 0000 0000 0000 0000 0101
      • 取反: 1111 1111 1111 1111 1111 1111 1111 1010
      • 反码: 1000 0000 0000 0000 0000 0000 0000 0101 [ 补码取反(符号位不变)]
      • 原码: 1000 0000 0000 0000 0000 0000 0000 0110[ 反码加 1,得到原码 ]

    一句话总结取反:

    • ~x = - (x + 1)
C++ 复制代码
#include <iostream>
using namespace std;
int main() {
    int a = 5;    // 二进制: 0000 0000 0000 0000 0000 0000 0000 0101
    int res = ~a;  //  取反: 1111 1111 1111 1111 1111 1111 1111 1010
    cout << "~" << a << " = " << res << endl;
    // 套入公式:~x = - (x + 1)
    // 输出: ~5 = -6(补码表示)
    return 0;
}

2.2.5 左移应用

规则:所有位向左移动,右边补0

C++ 复制代码
#include <iostream>

using namespace std;

int main() {
    int a = 5;    // 二进制: 0101
    int res = a << 2;  // 010100 = 20
    cout << a << " << 2 = " << res << endl;
    // 输出: 5 << 2 = 20
    return 0;
}

n << 1 等价于 n * 2

2.1.6 右移应用

规则:所有位向右移动

C++ 复制代码
#include <iostream>
using namespace std;
int main() {
    int a = 20;   // 二进制: 10100
    int res = a >> 2;  // 00101 = 5
    cout << a << " >> 2 = " << res << endl;
    // 输出: 20 >> 2 = 5
    return 0;
}

n >> 1 等价于 n / 2

**场景1:**二分查找

// 传统写法

int mid = (l+ r) / 2;

// 优化写法(防止溢出 + 性能更好)

int mid = l+ ((r- l) >> 1);

场景2:快速计算平均值

// 计算两个数的平均值

int avg= (a + b) >> 1;

// 比 (a + b) / 2 更快

场景3:循环减半

// 快速将数字减半直到0

while (n > 0) { cout << n << " "; n = n >> 1; // 快速除以2

}

【位运算技巧】

操作功能形象比喻n & (n-1)移除最低位的1摘果子n & (-n)保留最低位的1,其他全清0独留最右边的果子

举例子:n = 12 (二进制 1100)

n & (n-1)****:移除最低位的1

C++ 复制代码
n:     1 1 0 0  (12)
n-1:   1 0 1 1  (11)
       ----------- &
结果: 1 0 0 0  (8)   ← 移除了第2位的1

n & (-n)****:保留最低位的1

C++ 复制代码
n:     1 1 0 0  (12)
-n:    0 1 0 0  (-12,省略含符号的前4个1)
       ----------- &
结果: 0 1 0 0  (4)   ← 只保留了第2位的1

扩展:其他移位运算的数学意义

运算数学意义例子n << 1n * 25 << 1 = 10n << 2n * 45 << 2 = 20n << kn * 2^k3 << 3 = 24n >> 1n / 210 >> 1 = 5n >> kn / 2^k16 >> 2 = 4

口诀:左移翻倍,右移减半, 移位运算,速度飞快

相关推荐
笨蛋不要掉眼泪1 小时前
Java并发编程:线程的创建和运行
java·开发语言·jvm
九伯都1 小时前
java编写 agent 入门案例
java·开发语言
j7~1 小时前
【MYSQL】在Centos7和ubuntu22.04环境下安装
数据库·c++·mysql·ubuntu·centos
代码中介商1 小时前
C++ STL 容器完全指南(三):deque、list 与 map 深度详解
开发语言·c++
xqqxqxxq2 小时前
Java 线程池(一)
java·开发语言
eggrall2 小时前
Linux进程信号——像收快递一样理解 Linux 信号
linux·开发语言·c++
‎ദ്ദിᵔ.˛.ᵔ₎2 小时前
c++ 11左值和右值
c++
foundbug9992 小时前
MATLAB实现:基于图像对比度和波段相关性的高光谱波段选择算法
开发语言·算法·matlab
Hical_W2 小时前
C++ Web 框架性能实测(Benchmark)
c++·开源