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)
,实现了相同的功能。