BitSet 原理

BitSet 的特点是可以存储大量的数据,但使用很少的空间,原因就是使用 1 位(bit)表示 true/false

为了实现简单,我们规定记录数,然后就可以确定要使用的位数,从而可以确定需要的字节数,这里使用 uint64 作为最小的单位,最终通过 []uint64 存所有记录。

size := 100_000_000  
  
// uint64 数组长度  
bsLen := (size-1)/64 + 1  
words := make([]uint64, bsLen)  
  
// 设置为 true  
offset1 := 1000  
words[offset1/64] |= 1 << (offset1 % 64)  
  
// 判断是否为 true
offset2 := offset1 - 1  
exist := words[offset2/64]&(1<<(offset2%64)) != 0

offset/64 代表应该存储到哪个 uint64 ,通过 1 << (offset1 % 64) 找到对应 uint64 的哪一位,通过位或实现添加,位与判断是否存在。

清空(设置为 false

可以通过 bit clear(AND NOT) 实现清空:

words[offset3/64] &^= 1 << (offset3 % 64)
// 或者
words[offset3/64] &= ^(1 << (offset3 % 64))

计算 true 的个数

var count int  
for _, word := range words {
    count += bits.OnesCount64(word)  
}

bits.OnesCount64(x uint64) int Go 提供的函数,Java 可以参考 int bitCount(long i) ,实现了相同的功能。