位运算

竞赛/基础

位运算知识点总结

目录

  1. 基本运算符
  2. 运算符性质
  3. 经典例题
  4. [GESP 真题精选]
  5. [ 位运算实用技巧大全 ]

基本运算符

1. 左移运算符 <<

int a = 5;       // 二进制 00000101
int b = a << 2;  // 二进制 00010100 → 十进制20

- **功能**:将二进制数所有位向左移动,低位补0
    
- **数学意义**:相当于乘以2ⁿ(n为移动位数)
    

2. 右移运算符 >>

int a = 20;      // 二进制 00010100
int b = a >> 2;  // 二进制 00000101 → 十进制5
  • 功能:将二进制数所有位向右移动

  • 注意:对有符号数,高位补符号位(算术右移);对无符号数补0(逻辑右移)

3. 按位取反 ~


int a = 5;       // 00000101
int b = ~a;      // 11111010 → -6(补码表示)

4. 按位与 &

6 & 3 = 2        // 0110 & 0011 = 0010

5. 按位或 |

6 | 3 = 7        // 0110 | 0011 = 0111

运算符性质

交换律

a & b = b & a  
a | b = b | a

结合律

(a & b) & c = a & (b & c)  
(a | b) | c = a | (b | c)

分配律

a & (b | c) = (a & b) | (a & c)  
a | (b & c) = (a | b) & (a | c)

特殊性质

  1. 幂等律a & a = aa | a = a

  2. 吸收律a | (a & b) = aa & (a | b) = a

  3. 德摩根定律~(a | b) = ~a & ~b~(a & b) = ~a | ~b


经典例题

例题1:表达式计算

(15 >> 2) & (~(1 << 3)) = ?

解答

  1. 15 >> 2 = 3(二进制 0011

  2. 1 << 3 = 8(二进制 1000

  3. ~(8) = -9(二进制补码 11110111

  4. 3 & (-9) = 300000011 & 11110111 = 00000011

例题2:位运算应用

题目:用位运算判断奇偶

bool isOdd(int n) {
    return n & 1;  // 结果为1时是奇数
}

例题3:变量交换

a ^= b;
b ^= a;
a ^= b;  // 不使用临时变量交换a,b的值

GESP真题精选

2023年三级样题

题目:执行 (12 & 9) | (5 << 2) 的结果是?
A) 20
B) 21
C) 24
D) 25

解析

  1. 12 & 9 = 81100 & 1001 = 1000

  2. 5 << 2 = 200101 → 10100

  3. 8 | 20 = 20001000 | 10100 = 10100
    答案:A

2023年四级真题

题目:表达式 ~(0xFF << 4) 的二进制结果中最低的8位是?
A) 00001111
B) 11110000
C) 00000000
D) 11111111

解析

  1. 0xFF = 11111111

  2. << 4 → 11110000

  3. ~ → 00001111
    答案:A

位运算实用技巧大全

高效计算技巧

1. 快速乘除2的幂

n << 1;  // n*2
n >> 1;  // n/2(向下取整)
n << 3;  // n*8 (2³)

2. 判断奇偶性

if(n & 1) {
    // 奇数(二进制末位为1)
} else {
    // 偶数
}

3. 交换变量值(无需临时变量)

a ^= b;
b ^= a;
a ^= b;

4. 取绝对值(32位整数版)

int abs(int n) {
    return (n ^ (n >> 31)) - (n >> 31);
}

状态压缩应用

1. 集合表示(每个bit代表一个元素)

int set = 0;
set |= (1 << 3);  // 添加第3个元素
set &= ~(1 << 3); // 删除第3个元素
bool has = set & (1 << 3); // 检查第3个元素

2. 遍历子集

for(int subset = set; subset; subset = (subset-1) & set) {
    // 处理subset
}

3. 低效版(仅演示原理)

// 获取数字的二进制1的个数(汉明重量)
int count = 0;
while(n) {
    count += n & 1;
    n >>= 1;
}

算法优化技巧

1. 快速幂算法

int pow(int x, int n) {
    int res = 1;
    while(n) {
        if(n & 1) res *= x;
        x *= x;
        n >>= 1;
    }
    return res;
}

2. 检测2的幂次

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

3. 最低有效位(LSB)

int lsb = n & -n;  // 获取最右边的1

奇技淫巧

1. 字符大小写转换

char lower = ch | ' ';   // 转小写
char upper = ch & '_';   // 转大写
char toggle = ch ^ ' ';  // 大小写互换

2. 条件语句替代

// 代替 if(a>b) swap(a,b)
int diff = a ^ b;
int mask = (a - b) >> 31;
a ^= diff & mask;
b ^= diff & mask;

3. 模运算优化(仅适用于2ⁿ-1)

int mod = n & 0x0F;  // 等价于 n % 16

实战例题

例题1:找唯一出现数字

题目:数组中除一个数字出现1次外,其他都出现2次,找出该数字

int singleNumber(vector<int>& nums) {
    int res = 0;
    for(int num : nums) res ^= num;
    return res;
}

例题2:汉明距离

题目:计算两个整数二进制位不同的位数

int hammingDistance(int x, int y) {
    int diff = x ^ y, count = 0;
    while(diff) {
        diff &= diff - 1;
        count++;
    }
    return count;
}

例题3:位图排序

题目:对0-99的不重复数字排序(内存限制1KB)

unsigned char bitmap[16]; // 16*8=128bit
// 设置bit位
bitmap[n/8] |= (1 << (n%8));
// 检查bit位
if(bitmap[i/8] & (1 << (i%8)))

重要提示:位运算技巧虽然高效,但会降低代码可读性,实际开发中需权衡使用,建议添加详细注释说明原理。

posted @ 2025-09-24 17:10  stephen_zuo  阅读(23)  评论(0)    收藏  举报