1. BitMap介绍

BitMap能够了解为通过一个bit数组来存储特定数据的一种数据结构。BitMap罕用于对大量整形数据做去重和查问。
在这类查找中,咱们能够通过map数据结构进行查找。但如果数据量比拟大map数据结构将会大量占用内存。
BitMap用一个比特位来映射某个元素的状态,所以这种数据结构是十分节俭存储空间的。

BitMap用处

  • BitMap用于数据去重
    BitMap可用于数据的疾速查找,判重。
  • BitMap用于疾速排序
    BitMap因为其自身的有序性和唯一性,能够实现疾速排序:将其退出bitmap中,而后再遍历获取进去,从而失去排序的后果。

如何判断数字在bit数组的地位

在前面的代码中,咱们应用[]byte来存储bit数据,因为一个byte有8个二进制位。因而:

  • 数字/8=数字在字节数组中的地位。
  • 数字%8=数字在以后字节中的地位。
    例如:数字10,
  • 10/8=1,即数字10对应的字节数组的地位为:1
  • 10%8=2,即数字10对应的以后字节的地位为:2

设置数据到bit数组

  • num/8失去数字在字节数组中的地位 => row
  • num%8失去数字在以后字节中的地位 => col
  • 将1左移col位,而后和以前的数据做|运算,这样就能够将col地位的bit替换成1了。

从bit数组中革除数据

  • num/8失去数字在字节数组中的地位 => row
  • num%8失去数字在以后字节中的地位 => col
  • 将1左移col位,而后对取反,再与以后值做&,这样就能够将col地位的bit替换成0了。

数字是否在bit数组中

  • num/8失去数字在字节数组中的地位 => row
  • num%8失去数字在以后字节中的地位 => col
  • 将1左移col位,而后和以前的数据做&运算,若该字节的值!=0,则阐明该地位是1,则数据在bit数组中,否则数据不在bit数组中。

2. Go语言位运算

在Go语言中反对以下几种操作位的形式:

  • & 按位与:两者全为1后果为1,否则后果为0
  • | 按位或:两者有一个为1后果为1,否则后果为0
  • ^ 按位异或:两者不同后果为1,否则后果为0
  • &^ 按位与非:是"与"和"非"操作符的简写模式
  • << 按位左移:
  • >> 按位右移:

左移

将二进制向左挪动,左边空出的位用0填补,高位左移溢出则舍弃该高位。
因为每次移位数值会翻倍,所以通常用代替乘2操作。当然这是建设在移位没有溢出的状况。
例如:1<<3 相当于1×8=8,3<<4 相当于3×16=48

右移

将整数二进制向右挪动,右边空出的位用0或者1填补。负数用0填补,正数用1填补。
正数在内存中的二进制最高位为符号位——应用1示意,所以为了保障移位之后符号位的正确性,所以须要在高位补1。
绝对于左移来说,右移通常用来代替除2操作。
例如:24>>3 相当于24÷8=3

应用&^和位移运算来给某一地位0

这个操作符通常用于清空对应的标记位,例如 a = 0011 1010,如果想清空第二位,则能够这样操作:
a &^ 0000 0010 = 0011 1000

3. BitMap的Go语言实现

接下来咱们给出BitMap的Go语言实现,目前代码曾经上传到github中,下载地址

定义

首先给出BitMap构造的定义:

type BitMap struct {    bits []byte    vmax uint}

创立BitMap构造

func NewBitMap(max_val ...uint) *BitMap {    var max uint = 8192    if len(max_val) > 0 && max_val[0] > 0 {        max = max_val[0]    }    bm := &BitMap{}    bm.vmax = max    sz := (max + 7) / 8    bm.bits = make([]byte, sz, sz)    return bm}

将数据增加到BitMap

func (bm *BitMap)Set(num uint) {    if num > bm.vmax {        bm.vmax += 1024        if bm.vmax < num {            bm.vmax = num        }        dd := int(num+7)/8 - len(bm.bits)        if dd > 0 {            tmp_arr := make([]byte, dd, dd)            bm.bits = append(bm.bits, tmp_arr...)        }    }    //将1左移num%8后,而后和以前的数据做|,这样就替换成1了    bm.bits[num/8] |= 1 << (num%8)}

从BitMap中删除数据

func (bm *BitMap)UnSet(num uint) {    if num > bm.vmax {        return    }    //&^:将1左移num%8后,而后进行与非运算,将运算符右边数据相异的位保留,雷同位清零    bm.bits[num/8] &^= 1 << (num%8)}

判断BitMap中是否存在指定的数据

func (bm *BitMap)Check(num uint) bool {    if num > bm.vmax {        return false    }    //&:与运算符,两个都是1,后果为1    return bm.bits[num/8] & (1 << (num%8)) != 0}