BitSet源码解析,位运算玩的真六


引言

ArrayList 提供了一个方法 removeIf

其源码实现中,巧用 BitSet,惊艳到我了。

于是乎,拜读 BitSet 源码,位运算用的真6,服!!!


一、BitSet是什么?

我们常说的位图,在JAVA 中的实现,是 BitSet

也可以说是一种算法吧,很突出点:省空间

什么意思呢?举个简单的例子吧。

比如说有这么个场景:某基金的交易日记为1,休息日记为0,
那要记录一整年的数据,那就是 365 个数字,由1和0组成。
若数字是 int 类型,那 365 个数字,就是 1460 字节。
如果用 BitSet 来记录,理论上 48 个字节就可以了。

BitSet 使用 long 数组来记录数据,
long 8 个字节, 64 位,每位可对应一天的数据

比如第1天是交易日,在 long 的第 1 位,记录为 1,

第2天是休息日,在 long 的第 2 位,记录为 0,

以此类推,365 天, 6 个 long 就搞定。

BitSet 提供了一系列的方法,

封装位运算,方便使用。

这里写了个小 Demo,
在这里插入图片描述
图中 set (2) 就是 long 的 第 2 位 设置为 1

set (7) 就是 long 的 第 7 位 设置为 1,

bitSet.get(2) ,显示为 true该位是 1,就会返回 true
bitSet.get(5) ,显示为 false该位是 0,就会返回 false

先简单介绍下API,有个印象,之后再分析源码。

二、BitSet 常用方法

1、set(int bitIndex)
. 将对应下标位置的值设置为1

前面截图中的例子,说的不严谨,应该说下标位置。

调用 set (2)set (7) 后,对应的 long ,二进制应该是:10000100

如果调用 set (66) 时,那会怎么样呢?

一个 long 是 64 位,不够用了,

那会在 long 数组的第二个元素中进行操作,

也就是第二个 long,下标为 2 的位置,设置为1,

即 第二个 long 的二进制是:100

2、get(int bitIndex)
. 判断对应下标处是否为1,是1 返回 true, 否则返回 false

比如截图中的例子, get(2) 返回 true

调用 set (66) 时,会判断 第二个 long

其下标为2 的位置是否为1。

3、clear(int bitIndex))
. 将对应下标处的值清除

其实从方法的命名,也能猜到。说白了,就是把对应的下标处,设置为 0。

4、flip(int bitIndex))
. 将对应下标处的值反转

某下标处是1,调用该方法后变为0,
同样,本来是0,调用之后就变为1。

5、nextSetBit(int bitIndex))
. 从某下标处开始,第1个值为1的下标是多少

比如说,还是截图中的例子,调用 bitSet.nextSetBit(2),就会返回2
从下标为2开始判断,哪个位置值为1,当然就是 2 了。

调用 bitSet.nextSetBit(4),就会返回7,也很简单,
下标 4、5、6 的值都是 0,首次值为1,是下标7,所以返回 7。

如果不存在值为1的情况怎么办呢?
比如截图中的情况,调用 bitSet.nextSetBit(10)
返回 -1。

6、nextClearBit(int bitIndex))
. 从某下标处开始,第1个值为0的下标是多少

这个与上面的那个类似,不多解释了。

7、previousSetBit(int bitIndex))
8、previousClearBit(int bitIndex))

不多解释
下面几个是求交集、并集、补集,差集的

09、and(BitSet set) ----- 两者交集
10、or(BitSet set) ------- 两者全集
09、xor(BitSet set) ------- 两者全集减去交集,剩下的
10、andNot(BitSet set) ------- 前面的bit,去掉交集剩余的


三、BitSet 源码解析

1、初始化

初始化(不指定大小):BitSet bitSet = new BitSet();
初始化(指定了大小):BitSet bitSet = new BitSet(30);

初始化的相关代码,粘贴出来了


public class BitSet implements Cloneable, java.io.Serializable {
   
   

    private final static int ADDRESS_BITS_PER_WORD = 6;
    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
	
    private long[] words; // long 数组
    
    private transient int wordsInUse = 0;
    
    public BitSet() {
   
   
        initWords(BITS_PER_WORD); // 初始化数组大小
        sizeIsSticky = false;
    }

    public BitSet(int nbits) {
   
   
        if (nbits < 0)
            throw new NegativeArraySizeException("nbits < 0: " + nbits);
        initWords(nbits);
        sizeIsSticky = true;</
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值