位运算:从基础到实战,解锁高效编程的底层密码
1. 什么是位运算位运算Bitwise Operation是直接对整数在内存中的二进制位bit进行操作的一种运算方式。与常规的算术运算加减乘除不同位运算直接操作数据的底层二进制表示因此执行效率极高是编写高性能、低资源消耗代码的利器。在计算机中所有数据最终都以二进制形式存储。位运算让我们能够像操作开关一样精确地控制每一个二进制位0或1从而实现一些巧妙的算法和优化。2. 六大基本位运算符掌握位运算首先要理解以下六个核心运算符2.1 按位与规则两个位都为1时结果才为1否则为0。示例int a 5; // 二进制0101 int b 3; // 二进制0011 int result a b; // 结果0001 (十进制1) // 计算过程 // 0101 (5) // 0011 (3) // ---- // 0001 (1)常见用途判断奇偶(n 1) 0为偶数(n 1) 1为奇数取特定位value mask可以提取mask中为1的位清零特定位value ~mask可以将mask中为1的位清零2.2 按位或|规则两个位中只要有一个为1结果就为1。示例int a 5; // 0101 int b 3; // 0011 int result a | b; // 0111 (十进制7) // 计算过程 // 0101 (5) // | 0011 (3) // ---- // 0111 (7)常见用途设置特定位为1value | mask可以将mask中为1的位设置为1合并标志位多个布尔标志可以用一个整数的不同位表示2.3 按位异或^规则两个位不同时结果为1相同时结果为0。重要特性任何数与0异或等于本身a ^ 0 a任何数与自身异或等于0a ^ a 0满足交换律和结合律a ^ b b ^ a(a ^ b) ^ c a ^ (b ^ c)示例int a 5; // 0101 int b 3; // 0011 int result a ^ b; // 0110 (十进制6) // 计算过程 // 0101 (5) // ^ 0011 (3) // ---- // 0110 (6)常见用途交换两个数a a ^ b; b a ^ b; a a ^ b;找出现奇数次的数在一组数中只有一个数出现奇数次其他都出现偶数次加密解密用同一个密钥异或两次得到原文2.4 按位取反~规则将每一位取反0变11变0。注意在Java等有符号整数语言中取反操作包括符号位。示例int a 5; // 0000 0000 0000 0000 0000 0000 0000 0101 int result ~a; // 1111 1111 1111 1111 1111 1111 1111 1010 (十进制-6) // 这是补码表示实际值为-6常见用途创建掩码~0得到所有位都是1的数-1配合与运算清零特定位2.5 左移规则将二进制位全部向左移动指定位数低位补0。数学意义a n相当于a × 2ⁿ在不溢出的情况下。示例int a 5; // 0101 int result a 2; // 010100 (十进制20) // 相当于 5 × 2² 20常见用途快速乘以2的幂设置标志位1 n创建只有第n位为1的掩码2.6 右移 和 算术右移带符号右移高位补符号位正数补0负数补1。逻辑右移无符号右移高位总是补0。示例int a 8; // 1000 int b -8; // 1111 1111 1111 1111 1111 1111 1111 1000 int r1 a 2; // 0010 (2) 算术右移 int r2 a 2; // 0010 (2) 逻辑右移正数相同 int r3 b 2; // 1111 1111 1111 1111 1111 1111 1111 1110 (-2) int r4 b 2; // 0011 1111 1111 1111 1111 1111 1111 1110 (很大的正数)常见用途快速除以2的幂算术右移提取高位信息无符号处理逻辑右移3. 位运算的实战应用3.1 权限控制系统使用位运算实现简洁高效的权限控制public class PermissionSystem { // 定义权限常量使用2的幂次方 public static final int READ 1 0; // 0001 public static final int WRITE 1 1; // 0010 public static final int DELETE 1 2; // 0100 public static final int ADMIN 1 3; // 1000 private int permissions 0; // 添加权限 public void addPermission(int perm) { permissions | perm; } // 移除权限 public void removePermission(int perm) { permissions ~perm; } // 检查是否有权限 public boolean hasPermission(int perm) { return (permissions perm) ! 0; } // 检查是否只有指定权限没有其他权限 public boolean hasOnlyPermission(int perm) { return permissions perm; } // 切换权限有则移除无则添加 public void togglePermission(int perm) { permissions ^ perm; } }3.2 判断2的幂判断一个正整数是否是2的幂如1, 2, 4, 8, 16...public boolean isPowerOfTwo(int n) { // 2的幂的二进制表示只有一个1 // 例如8 10007 0111 // n (n-1) 会消去最低位的1 return n 0 (n (n - 1)) 0; }3.3 计算二进制中1的个数统计一个整数二进制表示中1的个数汉明重量public int countBits(int n) { int count 0; while (n ! 0) { n (n - 1); // 每次消去最低位的1 count; } return count; } // 或者使用内置方法Java public int countBitsBuiltin(int n) { return Integer.bitCount(n); }3.4 交换两个变量的值不使用临时变量public void swap(int a, int b) { a a ^ b; b a ^ b; // b (a ^ b) ^ b a a a ^ b; // a (a ^ b) ^ a b System.out.println(a a , b b); }3.5 找唯一出现一次的数字LeetCode经典题目给定一个非空整数数组除了某个元素只出现一次以外其余每个元素均出现两次。找出那个只出现了一次的元素。public int singleNumber(int[] nums) { int result 0; for (int num : nums) { result ^ num; // 利用 a ^ a 0 的特性 } return result; }4. 位运算的性能优势位运算之所以高效主要有以下几个原因硬件级支持CPU有专门的位运算指令执行速度极快内存访问少一次操作处理多个位减少内存访问次数无分支预测避免if-else等分支语句减少分支预测失败的开销并行处理可以同时对多个位进行操作性能对比示例// 传统方法判断奇偶 boolean isEven1(int n) { return n % 2 0; // 涉及除法运算 } // 位运算判断奇偶 boolean isEven2(int n) { return (n 1) 0; // 只需一次与运算 } // 测试表明位运算版本通常快2-5倍5. 注意事项与最佳实践5.1 优先级问题位运算符的优先级通常低于比较运算符使用时建议加括号// 错误先计算 1 1再与a进行与运算 if (a 1 1) { ... } // 正确明确优先级 if ((a 1) 1) { ... }5.2 符号扩展右移操作时要注意符号扩展问题特别是处理负数时byte b -1; // 11111111 int i b 4; // 算术右移11111111 11111111 11111111 11111111 (-1) int j b 4; // 逻辑右移00001111 11111111 11111111 11111111 (很大的正数)5.3 可读性与维护性虽然位运算高效但可读性较差。建议为复杂的位运算添加详细注释使用有意义的常量名代替魔数考虑使用枚举或常量类管理标志位在性能关键路径使用位运算其他情况优先考虑可读性5.4 平台兼容性不同语言、不同平台对位运算的实现可能有细微差异Java中整数固定为32位移位超过31位会取模C/C中移位超过位数是未定义行为Python整数无固定位数移位不会溢出6. 总结位运算作为编程中的屠龙技虽然日常开发中使用频率不高但在以下场景中不可或缺性能优化加密算法、压缩算法、图形处理系统编程操作系统内核、设备驱动、网络协议算法竞赛状态压缩、位掩码、快速幂嵌入式开发寄存器操作、硬件控制掌握位运算不仅能写出更高效的代码更能深入理解计算机底层的工作原理。建议从简单的应用开始练习逐步掌握这种强大的编程工具。学习建议理解二进制、原码、反码、补码的概念手动计算几个位运算的例子加深理解尝试用位运算解决LeetCode上的相关题目在实际项目中寻找可以使用位运算优化的场景