【数据结构中的位运算】


前言

在高性能算法与数据结构的设计中,位运算(Bitwise Operation)以其极低的时间常数和高效的空间利用,成为优化的利器。


一、位运算是什么?

位运算是直接对整数在 二进制位 级别进行的运算,常见操作符有:

  • &(按位与)
  • |(按位或)
  • ^(按位异或)
  • ~(按位取反)
  • <<(左移)
  • >>(右移)

与普通算术运算相比,位运算通常在 CPU 指令层面一条即可完成,性能极高。

二、使用步骤

1. 引入库

#include <iostream>
#include <bitset>   // 位图支持
#include <vector>
using namespace std;

2. 常用位运算示例

2.1 奇偶判断

如果 n & 1 == 0,则 n 为偶数;否则为奇数。

int n = 42;
if ( (n & 1) == 0 )
    cout << n << " 是偶数\n";
else
    cout << n << " 是奇数\n";

2.2 翻转所有位

~n 对 n 的每一位取反(注意符号位)。

int n = 5;          // 二进制:0000...0101
int m = ~n;         // m = 1111...1010,若 int32 约为 -6
cout << m << endl;

2.3 交换两个整数(无临时变量)

使用异或交换法:

int a = 3, b = 7;
a ^= b;  // a = a ^ b
b ^= a;  // b = b ^ (a ^ b) = 原 a
a ^= b;  // a = (a ^ b) ^ a = 原 b
cout << "a=" << a << ", b=" << b << endl;  // a=7, b=3

2.4 获取最低位的 1

lowbit = x & -x

int x = 12;         // 二进制:1100
int lowbit = x & -x;  // 0100(二进制的最低位 1)
cout << "lowest bit: " << lowbit << endl;

2.5 判断是否为 2 的幂

如果 x > 0 && (x & (x - 1)) == 0,则 x 是 2 的幂。

bool isPowerOfTwo(int x) {
    return x > 0 && (x & (x - 1)) == 0;
}

三、位运算在数据结构中的应用

1. 位图(Bitset)

当需要高效存储大量布尔标记时,std::bitset 能以 1 bit/标记 的方式节省空间,且支持所有位运算:

const int N = 1000;
bitset<N> vis;  // 初始化时全为 0

// 标记 10, 20, 30 为已访问
vis.set(10);
vis.set(20);
vis.set(30);

// 查询
if (vis.test(20)) cout << "20 已访问\n";

// 清除标记
vis.reset(20);

2. 二进制索引树(Fenwick Tree)

Fenwick Tree 中最经典的技巧是使用 i & -i 获得当前节点所负责的区间长度(lowbit),进而实现 O(log n) 的区间和与单点更新。

class Fenwick {
private:
    int n;
    vector<long long> tree;
    // lowbit: 返回 i 最低位的 1 所对应的值
    inline int lowbit(int i) { return i & -i; }

public:
    Fenwick(int _n): n(_n), tree(n + 1, 0) {}

    // 单点更新:index 增加 delta
    void update(int index, long long delta) {
        for (int i = index; i <= n; i += lowbit(i)) {
            tree[i] += delta;
        }
    }

    // 前缀和查询:[1..index]
    long long query(int index) {
        long long sum = 0;
        for (int i = index; i > 0; i -= lowbit(i)) {
            sum += tree[i];
        }
        return sum;
    }

    // 区间和查询:[l..r]
    long long rangeQuery(int l, int r) {
        return query(r) - query(l - 1);
    }
};

int main() {
    Fenwick fw(10);
    // 初始化:将第 3 号位置加 5
    fw.update(3, 5);
    // 查询前缀和
    cout << "sum[1..3] = " << fw.query(3) << endl;
    // 区间和
    cout << "sum[2..5] = " << fw.rangeQuery(2, 5) << endl;
    return 0;
}
  • 解释

    • lowbit(i) 提取出二进制中最低位的 1;
    • update 中,i += lowbit(i) 向后跳至下一个需要维护的节点;
    • query 中,i -= lowbit(i) 向前累加父节点的值。

总结

无论是节省空间的位图(bitset),还是依赖 i & -i 神技的 Fenwick Tree,位运算都能让你的代码更快、更简洁、更节省内存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wdwc2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值