位图是什么
位图可以理解为一个二进制位的数组,可以用位图来实现大规模数据的二值统计等功能
如何用go实现位图(主要接口)
用go语言实现位图首先要考虑的是底层的存储结构。go语言没有提供按位的个数开辟空间的功能,所以在存储时我们需要借助已经存在的数据类型来存储。
这里选择使用了字节切片作为底层的存储结构
type BitMap []byte
初始化位图
func New() *BitMap {
b := BitMap(make([]byte, 0))
return &b
}
设置某一位的值,当val大于0时会设置为1,否则设置为0
func (b *BitMap) SetBit(offset int64, val byte) {
byteIndex := offset / 8
bitOffset := offset % 8
mask := byte(1 << bitOffset)
b.grow(offset + 1)
if val > 0 {
// set bit
(*b)[byteIndex] |= mask
} else {
// clear bit
(*b)[byteIndex] &^= mask
}
}
获取某一位的值
func (b *BitMap) GetBit(offset int64) byte {
byteIndex := offset / 8
bitOffset := offset % 8
if byteIndex >= int64(len(*b)) {
return 0
}
return ((*b)[byteIndex] >> bitOffset) & 0x01
}
位图实现的完整代码
type BitMap []byte
func New() *BitMap {
b := BitMap(make([]byte, 0))
return &b
}
func toByteSize(bitSize int64) int64 {
if bitSize%8 == 0 {
return bitSize / 8
}
return bitSize/8 + 1
}
func (b *BitMap) grow(bitSize int64) {
byteSize := toByteSize(bitSize)
gap := byteSize - int64(len(*b))
if gap <= 0 {
return
}
*b = append(*b, make([]byte, gap)...)
}
func (b *BitMap) BitSize() int {
return len(*b) * 8
}
func FromBytes(bytes []byte) *BitMap {
bm := BitMap(bytes)
return &bm
}
func (b *BitMap) ToBytes() []byte {
return *b
}
func (b *BitMap) SetBit(offset int64, val byte) {
byteIndex := offset / 8
bitOffset := offset % 8
mask := byte(1 << bitOffset)
b.grow(offset + 1)
if val > 0 {
// set bit
(*b)[byteIndex] |= mask
} else {
// clear bit
(*b)[byteIndex] &^= mask
}
}
func (b *BitMap) GetBit(offset int64) byte {
byteIndex := offset / 8
bitOffset := offset % 8
if byteIndex >= int64(len(*b)) {
return 0
}
return ((*b)[byteIndex] >> bitOffset) & 0x01
}