go语言实现的位图

516 阅读1分钟

位图是什么

位图可以理解为一个二进制位的数组,可以用位图来实现大规模数据的二值统计等功能

如何用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
}