位图算法以及golang的简单实现。
一、位图算法介绍
位图(bitmap)算法原理:采用bit位来存储数据并建立相应映射关系。
位图(bitmap)算法优点:大大减少了存储空间,也加快了大量数据查询的时间。
位图(bitmap)算法缺点:当位图(bitmap)中存储的数据较少时,存入比较大的数值,会占用比较大的内存空间。
二、位图算法应用场景
位图算法应用场景如下:
1)单状态筛选,比如用户是否在线或者离线,可以根据用户数据库id当作查询数值,查询相应的位数。相应位数为1,即代表用户在线;相应位数为0,用户不在线。
2)多状态筛选,比如大量用户客户端,需要选择区域性的服务器服务,这时可以给服务器编号,根据服务器数量选择占用的位数来代表单个用户的服务器id,如果有4台服务器,就用两位来表示单个用户的服务器编号。
3)内存不足,大量确定范围的数值排序。
4)大量数据去重压缩,比如爬虫爬到的url去重。
三、Golang的简单实现
以下代码实现了1~2^63数值存储映射,输出是小端顺序,未补全0占位。
注:golang在64位机器中运行,int占用8byte,在32位机器中运行,int占用4byte。
type BitMap struct {
bitmap []byte
length int
}
func NewBitMap() *BitMap {
return &BitMap{}
}
func (bitmap *BitMap) Add(num int) {
if num == 0 {
return
}
byteIndex := num / 8
offsetIndex := num % 8
if byteIndex+1 >= bitmap.length {
if offsetIndex > 0 {
bitmap.bitmap = append(bitmap.bitmap, make([]byte, byteIndex-len(bitmap.bitmap)+1)...)
} else {
bitmap.bitmap = append(bitmap.bitmap, make([]byte, byteIndex-len(bitmap.bitmap))...)
}
}
if offsetIndex == 0 {
if byteIndex >= 1 {
bitmap.bitmap[byteIndex-1] |= 1
}
} else {
bitmap.bitmap[byteIndex] |= 1 << (8 - offsetIndex)
}
bitmap.length = len(bitmap.bitmap)
}
func (bitmap *BitMap) Del(num int) {
byteIndex := num / 8
offsetIndex := num % 8
if bitmap.Exist(num) {
if offsetIndex == 0 {
if byteIndex >= 1 {
if (bitmap.bitmap[byteIndex-1] & 1) != 0 {
bitmap.bitmap[byteIndex-1] &= ^uint8(1)
}
}
return
}
if bitmap.bitmap[byteIndex]&(1<<(8-offsetIndex)) != 0 {
bitmap.bitmap[byteIndex] &= ^uint8(1 << (8 - offsetIndex))
}
}
return
}
func (bitmap *BitMap) Exist(num int) bool {
if num == 0 {
return false
}
byteIndex := num / 8
offsetIndex := num % 8
if (byteIndex > bitmap.length) || (byteIndex == bitmap.length && offsetIndex > 0) {
return false
}
if offsetIndex == 0 {
if byteIndex >= 1 {
return bitmap.bitmap[byteIndex-1]&1 != 0
}
}
return bitmap.bitmap[byteIndex]&(1<<(8-offsetIndex)) != 0
}
func (bitmap *BitMap) Len() int {
return bitmap.length
}
func (bitmap *BitMap) ToString() string {
return fmt.Sprintf("%b", bitmap.bitmap)
}