当前位置: 首页 > news >正文

常见位运算技巧总结:从基础到高阶应用

一、基础位运算

1.基础位运算速查表

运算符名称行为描述示例(以a=60(00111100)b=13(00001101)为例)
&按位与同1得1,其余得0a & b → 12 (00001100)
|按位或有1得1a | b → 61 (00111101)
^按位异或不同得1,相同得0a ^ b → 49 (00110001)
~按位取反0变1,1变0(含符号位)~a → -61 (补码表示)
<<左移低位补0,高位溢出丢弃a << 2 → 240 (11110000)
>>右移高位补符号位,低位溢出丢弃-8 >> 1 → -4(带符号右移)

2.位运算优先级 

完整优先级列表​(从高到低):

运算符描述示例注意事项
~按位取反~a单目运算符,最高优先级
<< >> >>>位移运算a<<2优先级低于算术运算符
&按位与a & b高于比较运算符
^按位异或a ^ b优先级高于逻辑或
``按位或`a

常见错误示例

// 错误:实际等价于 a & (1 == 0)
if (a & 1 == 0) { ... }

// 正确写法
if ((a & 1) == 0) { ... }

 3.异或运算运算律

数学性质

  1. 交换律a ^ b = b ^ a
  2. 结合律(a ^ b) ^ c = a ^ (b ^ c)
  3. 自反性a ^ a = 0
  4. 恒等律a ^ 0 = a
  5. 可逆性:若 a ^ b = c,则 c ^ b = a

重要限制

  • 不满足分配律:a ^ (b & c) ≠ (a ^ b) & (a ^ c)
  • 不能直接用于非整型数据(浮点数需特殊处理)

二、高频操作技巧

1.判断二进制第x位是0还是1

public class BitCheck {
    // 方法1:使用位掩码(推荐,正确处理负数)
    public static boolean isBitSet(int n, int x) {
        return (n & (1 << x)) != 0;
    }

    // 方法2:右移后与1比较(注意符号位影响)
    public static boolean isBitSetByShift(int n, int x) {
        return ((n >> x) & 1) == 1;
    }

    public static void main(String[] args) {
        int num = 0b1001; // 二进制1001(十进制9)
        System.out.println(isBitSet(num, 3));    // true(第3位是1)
        System.out.println(isBitSet(num, 2));    // false(第2位是0)
    }
}

关键点:​

  • 位掩码原理1 << x 生成形如 000...100... 的掩码,与 n 进行 & 操作后,仅保留目标位
  • 负数处理:使用方法1可正确处理负数,右移方法在负数高位会补1
  • 参数校验:建议添加 if (x < 0 || x > 31) throw...

 2.将第x位修改为1

public class BitSetter {
    public static int setBit(int n, int x) {
        return n | (1 << x);
    }

    public static void main(String[] args) {
        int num = 0b1001; // 原值9(1001)
        int result = setBit(num, 2);
        System.out.println(Integer.toBinaryString(result)); // 1101(13)
    }
}

核心逻辑:​

  • 或操作特性0 | 1 = 11 | 1 = 1,保证目标位被置1
  • 示例流程
    原始值:1001
    掩码:  0100 (1 << 2)
    结果:  1101 (1001 | 0100)
  • 数据类型扩展:处理long时需用 1L << x

3:将第x位修改为0

public class BitClear {
    public static int clearBit(int n, int x) {
        return n & ~(1 << x);
    }

    public static void main(String[] args) {
        int num = 0b1001; // 原值9(1001)
        int result = clearBit(num, 3);
        System.out.println(Integer.toBinaryString(result)); // 0001(1)
    }
}

实现原理:​

  • 取反掩码~(1 << x) 生成形如 111...011... 的掩码
  • 与操作特性0 & 0 = 01 & 0 = 0,强制清除目标位
  • 操作示例
    原始值:1001
    取反掩码:0111 (~1000)
    结果:  0001 (1001 & 0111)

4.提取最右侧的1 

public class RightmostOne {
    // 获取最右侧1的数值(例如12=1100返回4=100)
    public static int getRightmostOne(int n) {
        return n & -n;
    }

    // 获取最右侧1的位置索引(例如12=1100返回2)
    public static int getRightmostOnePosition(int n) {
        return Integer.numberOfTrailingZeros(n & -n);
    }

    public static void main(String[] args) {
        System.out.println(getRightmostOne(12));       // 4 (二进制100)
        System.out.println(getRightmostOne(7));        // 1 (二进制001)
        System.out.println(getRightmostOnePosition(12)); // 2(第2位)
    }
}

实现原理:​

  1. 二进制补码特性-n 是 n 的二进制补码(取反+1)
  2. 位与操作n & -n 会保留最右侧的1,其他位清零
    示例:n=12 (1100)
    -n = 补码 0100
    1100 & 0100 = 0100 (十进制4)

5.清除最右侧的1 

public class ClearRightmostOne {
    public static int clearRightmostOne(int n) {
        return n & (n - 1);
    }

    public static void main(String[] args) {
        System.out.println(clearRightmostOne(12)); // 8 (1000 -> 清除1100的最右侧1)
        System.out.println(clearRightmostOne(7));  // 6 (清除0111的最右侧1得0110)
        System.out.println(clearRightmostOne(1));  // 0 
    }
}

核心逻辑:​

  1. 减1操作n-1 会将最右侧的1变为0,右侧所有0变为1
  2. 与操作n & (n-1) 清除变化的位
    示例:n=12 (1100)
    n-1=11 (1011)
    1100 & 1011 = 1000 (十进制8)

 

三.位图思想(Bitmap)​

核心概念:使用二进制位(bit)作为存储单元,通过位的位置(offset)映射数据索引,每位0/1表示存在与否。

核心优势

  1. 空间效率:1个int(32位)可存储32个状态,空间压缩率高达32倍
  2. 操作高效:位运算指令直接在寄存器执行,时间复杂度O(1)

典型应用场景

  • 海量数据去重(布隆过滤器)
  • 权限控制系统(每位代表一个权限)
  • 图像二值化处理
public class Bitmap {
    private int[] bits;
    
    // 初始化位图(存储maxSize个元素)
    public Bitmap(int maxSize) {
        bits = new int[(maxSize >> 5) + 1]; // 除以32并向上取整
    }

    // 设置某位为1
    public void set(int pos) {
        int arrIdx = pos >> 5;    // 确定在哪个int
        int bitIdx = pos & 0x1F;  // 取低5位确定具体bit
        bits[arrIdx] |= (1 << bitIdx);
    }

    // 检查某位是否为1
    public boolean get(int pos) {
        int arrIdx = pos >> 5;
        int bitIdx = pos & 0x1F;
        return (bits[arrIdx] & (1 << bitIdx)) != 0;
    }
}

相关文章:

  • thunder bird 配置邮箱
  • @Async与@EnableAsync有10个定时任务接口,只执行了8个
  • 利用PHP爬虫获取17网(17zwd)商品详情:实战指南
  • 设计模式之迭代器模式
  • 无人机接替通航应急优势及技术分析
  • 【星云 Orbit•STM32F4】13. 探索定时器:基本定时器
  • 碰一碰发视频系统之写卡功能开发了,支持OEM
  • 【Git】linux搭建Gitea配置mysql数据库
  • Redis特性总结
  • Sqlserver安全篇之_手工创建TLS用到的pfx证书文件
  • AAA协议:从零认识网络的“身份管家”
  • springboot3 WebClient
  • HTML 编辑器推荐与 VS Code 使用教程
  • 从信息收集到重置教务密码
  • 练习题:70
  • 调研:如何实现智能分析助手(Agent)(AutoCoder、FastGPT、AutoGen、DataCopilot)
  • 递归、搜索与回溯第二讲:二叉树中的深搜 穷举vs暴搜vs深搜vs回溯vs剪枝
  • go切片定义和初始化
  • 批量删除 Word 文档的水印
  • Potplayer 怎么用鼠标左键单击播放暂停
  • 做计划网站/百度关键词排名代发
  • 在香港做网站需要什么软件/一站式软文发布推广平台
  • 1688网站建设方案书模板/百度信息流怎么投放
  • 网站防劫持怎么做/企业宣传册
  • 简洁网站设计/图片优化
  • 厦门做网站找哪家公司/信息流投放