Skip to content

第 22 节:位运算

课程目标:

  • 理解基本的位运算符及其用法。
  • 掌握位运算在实际编程中的应用。
  • 能够使用位运算解决常见问题。

1. 课程导入 1

  • 位运算的意义:本质性,二是计算机底层就是二值逻辑

2. 位运算符介绍 3

  • 按位与 (&)

    cpp
    #include <iostream>
    using namespace std;
    
    int main() {
        unsigned int a = 3;  // 11 in binary
        unsigned int b = 5;  // 101 in binary
        cout << "a & b: " << (a & b) << endl; // 输出 1 (001 in binary)
        return 0;
    }
    • 按位或 (|)
    cpp
    #include <iostream>
    
    int main() {
        int a = 2;  // 10 in binary
        int b = 6;  // 110 in binary
        std::cout << "a | b: " << (a | b) << std::endl; // 输出 6 (110 in binary)
        return 0;
    }
  • 按位异或 (^)

    cpp
    #include <iostream>
    
    int main() {
        int x = 12; // 1100 in binary
        int y = 25; // 11001 in binary
        std::cout << "x ^ y: " << (x ^ y) << std::endl; // 结果为 21 (10101 in binary)
        return 0;
    }
  • 按位取反 (~)

    cpp
    #include <iostream>
    
    int main() {
        unsigned int n = 1; // 00000001 in binary
        std::cout << "~n: " << (~n) << std::endl; // 注意:结果取决于系统位数
        return 0;
    }
  • 左移 (<<)、右移 (>>)

    cpp
    #include <iostream>
    
    int main() {
        int z = 1; // 00000001
        std::cout << "z << 2: " << (z << 2) << std::endl; // 00000100 (4 in decimal)
        std::cout << "z >> 1: " << (z >> 1) << std::endl; // 00000000 (0 in decimal)
        return 0;
    }

3. 应用示例与实践 9

  • 使用位运算进行权限控制

    cpp
    #include <iostream>
    
    void checkPermission(int permissions, int requiredPermission) {
        if (permissions & requiredPermission) {
            std::cout << "Permission granted." << std::endl;
        } else {
            std::cout << "Permission denied." << std::endl;
        }
    }
    
    int main() {
        int userPermission = 0b0101; // 读和写权限
        checkPermission(userPermission, 0b0001); // 检查读权限
        checkPermission(userPermission, 0b0010); // 检查写权限 
        return 0;
    }
  • 使用位运算交换两个数

    cpp
    #include <iostream>
    
    void swap(int &a, int &b) {
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
    }
    
    int main() {
        int x = 4, y = 5;
        swap(x, y);
        std::cout << "x: " << x << ", y: " << y << std::endl;
        return 0;
    }

4. 深入探讨:位运算的高级用法 4

  • 查找唯一的数字

    cpp
    #include <iostream>
    #include <vector>
    
    int singleNumber(std::vector<int>& nums) {
        int result = 0;
        for(int num : nums) {
            result ^= num;
        }
        return result;
    }
    
    int main() {
        std::vector<int> numbers = {4,1,2,1,2};
        std::cout << "The single number is: " << singleNumber(numbers) << std::endl;
        return 0;
    }

6. std::bitset 的使用 3

  • 什么是 std::bitset

    • std::bitset 是一个固定大小的位序列,可以像对待数组一样处理位,非常适用于需要位运算的场景。
  • 如何使用 std::bitset

    a. 初始化和设置位

    cpp
    #include <iostream>
    #include <bitset>
    
    int main() {
        // 创建一个包含4位的bitset,所有位初始为0
        std::bitset<4> bset1;
        // 通过字符串初始化bitset
        std::bitset<4> bset2("1011");
        
        std::cout << "bset1: " << bset1 << std::endl;
        std::cout << "bset2: " << bset2 << std::endl;
    
        // 设置某一位为1或0
        bset1[1] = 1; // 设置第二位为1
        std::cout << "After setting: " << bset1 << std::endl;
        
        return 0;
    }

    b. 常用操作

    cpp
    #include <iostream>
    #include <bitset>
    
    int main() {
        std::bitset<4> bset1(9); // 1001
        std::bitset<4> bset2(5); // 0101
    
        // 按位逻辑运算
        std::cout << "bset1 & bset2: " << (bset1 & bset2) << std::endl;
        std::cout << "bset1 | bset2: " << (bset1 | bset2) << std::endl;
        std::cout << "bset1 ^ bset2: " << (bset1 ^ bset2) << std::endl;
    
        // 翻转所有位
        std::cout << "~bset1: " << (~bset1) << std::endl;
    
        // 测试某一位
        std::cout << "Is the second bit of bset1 set? " << bset1.test(1) << std::endl;
        
        return 0;
    }

    c. 转换功能

    cpp
    #include <iostream>
    #include <bitset>
    #include <string>
    
    int main() {
        std::bitset<4> bits("1010");
        // 转换为字符串
        std::string str = bits.to_string();
        std::cout << "String representation: " << str << std::endl;
    
        // 转换为无符号长整数
        unsigned long num = bits.to_ulong();
        std::cout << "As unsigned long: " << num << std::endl;
    
        // Note: 当bitset的大小超过unsigned long的位数时,会抛出overflow_error
        try {
            std::bitset<33> tooLarge(1);
            tooLarge.to_ulong(); // This will throw
        } catch(const std::exception& e) {
            std::cerr << "Error: " << e.what() << std::endl;
        }
        
        return 0;
    }

课后作业 4

  • 作业:
    • 使用位运算编写一个程序,该程序能够将一个整数的第n位进行翻转(0变1,1变0)。
cpp
#include <iostream>
#include <bitset>
#include <stdexcept>

template<int Size>
class BitSet {
public:
    BitSet(int n) : bits(n) {}  // 模板构造函数,无需参数,直接使用模板参数Size

    void flip(int n) {
        bits.flip(n);
    }

    bool check(int n) {
        return bits.test(n);
    }

private:
    std::bitset<Size> bits; // 使用模板参数来定义bitset的大小
};

int main() {
    try {
        BitSet<10> bs(1);  // 现在可以用任意的大小来初始化BitSet了
        bs.flip(2);
        std::cout << "Bit at position 2 is: " << (bs.check(2) ? "set" : "not set") << std::endl;

        // 测试越界的情况
        bs.check(10); // 这会抛出异常
    } catch (const std::exception& e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    }

    return 0;
}