操作命令
setbit :为位数组指定偏移量上的二进制位设置值,偏移量从0开始计数,二进制位的值只能为0或1.
getbit:获取指定偏移量上二进制位的值
bitcount:统计数组中值为1的二进制位数量
bitop:对多个位数组进行按位与,或,异或运算。
bitmap使用的数据结构是SDS动态字符串
如下展示了一个有SDS表示的一字节长的位图
redis中的每个对象都有一个redisObject结构表示的
typedef struct redisObject { // 类型 unsigned type:4; // 编码 unsigned encoding:4; unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */ // 引用计数 int refcount; // 执行底层实现的数据结构的指针 void *ptr; } robj;
type的值为REDIS_STRING表示这是一个字符串对象
sdshdr.len的值为1表示这个SDS保存了一个1字节大小的位数组
buf数组中的buf[0]实际保存了为数组
buf数组中的buf[1]为自动追加的\0字符
GETBIT
GETBIT用于返回位数组在偏移量上的二进制位的值。时间复杂度位O(1)
GETBIT命令的执行过程:
1.计算byte=「offset / 8」,byte 值表示指定的offset位于位数组的那个字节
2.指定buf[i]中的i,接下来就要计算在8个字节中的第几位 ,bit=(offset % 8)+1
3.根据byte和bit在位数组中定位到目标值
SETBIT
SETBIT用于将位数组在偏移量的二进制位的值设为value,并向客户端返回旧值
1.计算len=(offset / 8)+1 ,len值记录了保存offset偏移量指定的二进制至少需要多少个字节
2.检查位数组的长度是否小于len,如果是的话,将sds 的长度扩展为len字节 ,并将所有新扩展空间的二进制设置为0
3.计算byte=(offset / 8),byte值表示指定的offset位于数组的那个字节
4.使用bit=(offset mod 8)+ 1 计算可得目标buf【i】的具体第几位
5.根据byte和bit的值,首先保存oldvalue,然后将新值value设置到目标位上
6.返回旧值
BITCOUNT
bitcount命令用于统计给定位数组中值为一的二进制位的数量
两种可用的方法
1.查表法
对于一个有限集合来说,集合元素的排列方式是有限的,并且对于一个有限长度的位数组来说,它能表示的二进制位排列也是有限的。根据这个原理,我们可以创建一个表,表的键为某种排列的位数组,而表的值则是相应位数组中值为1的二进制位的数量。
对于8位长的位数组来说,我们可以创建下表,通过这个表格我们可以一次从位数组中读入8位,然后根据这8位的值进行查表,直接知道这个值包含了多少个1。
缺点:浪费内存
2.二进制位统计算法:variable-precision SWAR
还没学会