Golang下基于uint32的BitMap类库

关注点:
目标:BitMap的目标是用更小的内存空间,存放更多的key的状态(仅支持1、0状态,如果需要支持更多的状态,那么就得用更多的字节来表达value)
思路:
使用golang下的uint32类型的数组来实现,原因有2点:
  (1)uint32位数组,定长,数组中每个元素都是一个uint32的整型,占4个字节,32个bit位。
  (2)uint32位的值,是无符号类型,每个值的32个bit位都可以利用上。




package tools

import (
"fmt"
"strconv"
)

type BitMapTool struct {
Capacity int64
BitMapLength int64
BitMapArray []uint32
}

//region 初始化指定容量的BitMap,使用uint32类型的数组
func (this *BitMapTool) Init(capacity int64){
this.Capacity=capacity
this.BitMapLength=int64((capacity+31)/32)
fmt.Printf("定义BitMap,容量:%d,数组长度:%d\n",capacity,this.BitMapLength)
this.BitMapArray=make([]uint32,this.BitMapLength)
}
//endregion

//region 设置第N个位置的值为1,即true
func (this *BitMapTool) SetValue(key int64,value bool){
idx:=uint32((key-1)/32)
pos:=uint32((key-1) % 32)

var oldArrayValue,newArrayValue uint32
oldArrayValue=this.BitMapArray[idx]
fmt.Printf("数组位置:%d,原值:%d,二进制值:%s\n",idx,oldArrayValue,this.ConverToBianry(oldArrayValue))

if value{
// 目标:设置pos位置的bit位的值为1
// 用1左移pos的位数,得到0000100...,再与原值进行“与”运算,这样讲指定位置的bit位置为1
newArrayValue=((uint32(1) << pos)|oldArrayValue)
}else{
// 目标:设置pos位置的bit位的值为0
// 以pos位置为分割点,将原值分为左右两个二进制串,将原值右移pos的位数,得到原值左边的串,将原值左移(32-pos)的位数,得到原值右边的串,再将左右两个串进行“或”运算
tempLeftValue:=oldArrayValue>>pos
tempRightValue:=oldArrayValue<<(32-pos)
newArrayValue=tempLeftValue|tempRightValue
}

fmt.Printf("数组位置:%d,新值:%d,二进制值:%s\n",idx,newArrayValue,this.ConverToBianry(newArrayValue))

this.BitMapArray[idx]=newArrayValue
}
//endregion


//region 取出第N个位置的bit位的值,判断该值是否存在,true为存在,false为不存在
func (this *BitMapTool) GetValue(value int64)(ret bool){
idx:=uint32((value-1)/32)
pos:=uint32((value-1) % 32)

var oldArrayValue uint32
oldArrayValue=this.BitMapArray[idx]
fmt.Printf("数组位置:%d,当前值:%d,二进制值:%s\n",idx,oldArrayValue,this.ConverToBianry(oldArrayValue))

retstr:="不存在"
newValue:=(uint32(1) << pos)&oldArrayValue
if(newValue==0){
ret=false
}else{
ret=true
retstr="存在"
}
fmt.Printf("数组位置:%d,与1<<%d的与计算值:%d,二进制值:%s,结论:%t-%s\n",idx,pos,newValue,this.ConverToBianry(newValue),ret,retstr)
return ret
}
//endregion

//region 将整型数值转换为二进制字符串
func (this *BitMapTool) ConverToBianry(n uint32) string {
result := ""
for ; n > 0; n /= 2 {
lsb := int(n % 2)
result = strconv.Itoa(lsb) + result
}
return result
}

//endregion

    




单元测试部分:
package unittest

import (
"fmt"
"jinou/autowatch/tools"
"testing"
)


var Bitmap tools.BitMapTool

func TestBitMap(t *testing.T) {
a:=64
fmt.Printf("%d \n",a)
Bitmap.Init(64)

Bitmap.SetValue(int64(1),true)
Bitmap.SetValue(int64(7),true)
Bitmap.SetValue(int64(10),true)
Bitmap.SetValue(int64(64),true)

Bitmap.GetValue(int64(1))
Bitmap.GetValue(int64(2))
Bitmap.GetValue(int64(3))
Bitmap.GetValue(int64(7))
Bitmap.GetValue(int64(10))
Bitmap.GetValue(int64(64))

Bitmap.SetValue(int64(7),false)
Bitmap.SetValue(int64(10),false)

Bitmap.GetValue(int64(7))
Bitmap.GetValue(int64(10))

}

posted on 2022-01-31 17:18  李军浩  阅读(568)  评论(0编辑  收藏  举报

导航