位运算的使用

  1. 背景

​ 工作中依赖外部团队使用了位运算对数据进行了转化和存储。

​ 今天整理下关于位运算相关的内容。

  1. 位运算基础

    现代计算机中所有的数据以二进制的形式存储在设备中。即 0、1 两种状态,计算机对二进制数据进行的运算(+、-、*、/)都是叫位运算,即将符号位共同参与运算的运算。

符号描述运算规则
&两个位都为1时,结果才为1
l两个位都为0时,结果才为0
^异或两个位相同为0,相异为10^0=0 0^1=1 1^0=1 1^1=0
~取反0变1,1变0
<<左移各二进位全部左移若干位,高位丢弃,低位补0
>>右移各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)
  1. 使用场景

1) 源码中使用
位运算计算速度快。 LIst,map源码中使用。 如arrayList 扩容

在这里插入图片描述
2)状态位标识

​ 商品的属性有很多: 是否新品,是否虚拟商品,是否图书,是否支持配送,是否参加营销活动。

​ 10110; 我们可以表示 新品图书且支持配送。

​ 3)数据状态整合

​ 比如本文背景中说到的,将主类型 移位后,和子类型运算,整合成一个数值。

  1. 举个例子

    记录员工本周(月)打卡情况。
    场景: 记录员工本周(月)打卡情况。
    实现: 使用位运算-实现统计周打卡的类。

            1)签到方法;取消签到方法;统计总数;获取签到数据;查看某天是否签到等
    
            2)定义枚举,原来标识状态。本例中标识 每天的签到情况。
    
/**
* 记录周打卡的实现类
*/
public class WeekSign {

    //本周签到状态
    private static int status;

    //设置签到状态
    public static void setStatus(int status){
        WeekSign.status = status;
    }

    /**
     * 获取周签到记录
     * @return
     */
    public static String getWeeKSignRecord(){
        System.out.println("签到状态值为:"+status);
         return Integer.toBinaryString(status);
    }

    /**
     * 周签到总数
     * @return
     */
    public static int getWeeKSignRecordCount(){
        return Integer.bitCount(status);
    }

    /**
     * 添加签到 (打标)
     * @param
     */
    public static void addSign(WeekSignEnum xDay){

        if( (status & xDay.getValue()) == xDay.getValue() ){
            System.out.println(xDay.getName()+"已签到,无需重复签到");
           return;
        }
        status = status | xDay.getValue();
    }

    /**
     * 取消签到(取消打标)
     * @param xDay
     */
    public static void removeSign(WeekSignEnum xDay){

        if( (status & xDay.getValue()) != xDay.getValue() ){
            System.out.println(xDay.getName()+"未签到,无需取消签到");
            return;
        }
        //异或运算
        status = status ^ xDay.getValue();
    }

    /**
     * 判断哪天是否签到 (判断某个标识)
     * @param xDay
     */
    public  static  void  getXdayIsSign(WeekSignEnum xDay){
        if( (status & xDay.getValue()) == xDay.getValue() ){
           System.out.println(xDay.getName()+":签到了");
        }else{
            System.out.println(xDay.getName()+":缺勤");
        }
    }
   
     /**
     * 内部枚举定义
     */
    enum WeekSignEnum {

        day01Sign("周一",1),
        day02Sign("周二",2<<0),
        day03Sign("周三",2<<1),
        day04Sign("周四",2<<2),
        day05Sign("周五",2<<3),
        day06Sign("周六",2<<4),
        day07Sign("周日",2<<5);


        private String name;

        //某天签到的标记值
        private int  value;


        WeekSignEnum(String name, int value) {
            this.name = name;
            this.value = value;
        }

        public String getName() {
            return name;
        }

        public int getValue() {
            return value;
        }
    }

}

​ 测试“签到打卡”类

 public void multiBooleanStatusBitStore() {

        //WeekSign.setStatus(WeekSign.WeekSignEnum.day01Sign.getValue() | WeekSign.WeekSignEnum.day03Sign.getValue());
        //打卡签到
        WeekSign.addSign(WeekSign.WeekSignEnum.day01Sign);
        WeekSign.addSign(WeekSign.WeekSignEnum.day02Sign);
        WeekSign.addSign(WeekSign.WeekSignEnum.day03Sign);
        WeekSign.addSign(WeekSign.WeekSignEnum.day04Sign);
        WeekSign.addSign(WeekSign.WeekSignEnum.day05Sign);
        WeekSign.addSign(WeekSign.WeekSignEnum.day07Sign);

        //重复打卡
        WeekSign.addSign(WeekSign.WeekSignEnum.day05Sign);

        //取消签到
        WeekSign.removeSign(WeekSign.WeekSignEnum.day02Sign);

        //重复取消签到
        WeekSign.removeSign(WeekSign.WeekSignEnum.day02Sign);

        //总的情况
        System.out.println("本周签到记录(二进制):" + WeekSign.getWeeKSignRecord());
        System.out.println("本周一共签到天数:" + WeekSign.getWeeKSignRecordCount());

        //判断某天 是否签到
        WeekSign.getXdayIsSign(WeekSign.WeekSignEnum.day03Sign);
        WeekSign.getXdayIsSign(WeekSign.WeekSignEnum.day05Sign);

    }

效果
在这里插入图片描述

  1. 其他

​ Q: 有 1000 个一模一样的瓶子,其中有 999 瓶是普通的水,有1瓶是毒药。现在,如果检验出哪个瓶子里有毒药,(一定时间内)最少需要几只小老鼠试毒。

   A: log2 ​1000   = 10只。

   解释:  以8瓶水为例,log2  8 = 3只。         

          将水瓶编号,将(二进制)对应位数为1的水喂给同一个小老鼠。一定时间后 看有哪些小老鼠GG了。

           如:B和C 小老鼠G了, 说明  【0 1 1】  水瓶有毒。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值