关注点:
目标: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))
}