redis-整数集合
来源:互联网 发布:广州多想网络 骗 编辑:程序博客网 时间:2024/06/08 16:37
redis- 整数集合
整数集合(intset)是集合键的底层实现之一。当一个集合只包括整数元素并且元素个数不多时,Redis将会使用整数集合来存储。
看下面例子,当集合s1只存储整数1、2、4时,底层采用intset来存储;往集合s1中添加字符串”hello”后,底层存储变为哈希表。
redis的集合数据结构(set)其实是利用哈希表实现的,哈希表的键就是集合的元素,哈希表的值都是NULL。
127.0.0.1:6379> sadd s1 1 2 4(integer) 3127.0.0.1:6379> object encoding s1"intset"127.0.0.1:6379> sadd s1 "hello"(integer) 1127.0.0.1:6379> object encoding s1"hashtable"
以下片断是t_set.c
的部分代码,从注释中可以看到,当值是一个整数值时返回intset,否则返回一个hashtable。
/* Factory method to return a set that *can* hold "value". When the object has * an integer-encodable value, an intset will be returned. Otherwise a regular * hash table. */robj *setTypeCreate(robj *value) { if (isObjectRepresentableAsLongLong(value,NULL) == C_OK) return createIntsetObject(); return createSetObject();}
整数集合的实现
redis整数集合可以存储int16_t、int32_t或者int64_t类型的整数值,并且保证集合中不存在重复元素。
redis的整数集合定义如下:
typedef struct intset { //编码方式 uint32_t encoding; //集合包含的元素数量 uint32_t length; //保存元素的数组 int8_t contents[];} intset;
- encoding:整数集合保存的数据类型,encoding属性取值范围包括:
- INTSET_ENC_INT16,此时contents数组元素值的范围为[-2^15^, 2^15^-1]
- INTSET_ENC_INT32,此时contents数组元素值的范围为[-2^31^, 2^31^-1]
- INTSET_ENC_INT64,此时contents数组元素值的范围为[-2^63^, 2^63^-1]
- length:整数集合包含的元素数量,也就是contents数组的大小
- contents:实际存储元素的数组,虽然contents数组的类型声明为int8_t,但是实际使用是根据encoding来决定数组存储的整数类型的。另外,contents中的元素是根据元素大小从小到大排列的,且contents中不存在任何重复项。
图1
图1是一个包括6个元素的整数集合,其中元素是int16_t类型的。
升级
对于图1的例子,如果此时往该整数集合插入一个int32_t类型的值,比如插入2010483000,显然原来的int16_t类型存储不了该值,此时需要对整数集合进行升级。
升级步骤为:
- 根据新元素的类型,扩展底层存储空间的大小,并为新添加的元素预留存储空间。
- 调整原有数据的数据类型为新的数据类型,预留每个元素的空间。
- 将新添加的元素放到整数集合的正确位置。
例如对于图1,此时要插入2010483000,需要将原有的数据类型升级为int32_t
- 首先计算需要的空间大小。元素个数有7个,每个大小为32位,总共有7x32=224位,空间分配如图2。
图2
从图2可以看出,新分配的空间位数为96-223位。
元素198排在第6位,所以它的最终位置为160-191位;
元素89排在第5位,所以它的最终位置为128-159位;
元素45排在第4位,所以它的最终位置为96-127位;
元素23排第3位,所以它的最终位置为64-95位;
元素-456排在第2位,所以它的最终位置为32-63位;
元素-1234排在第1位,所以它的最终位置为0-31位;
最终如图3所示
图3
新插入的元素放到第7位的空间,最终如图4所示。
图4
最后程序将encoding属性值改为INTSET_ENC_INT32,将length属性值改为7。
注意:如果新添加的元素引起了整数集合的升级,那么这个元素要么是比原来所有的元素都大,要么比原来所有的元素都小(负数)。因此新添加的元素要么位于数组contents索引0处,要么位于数组末尾。
为何要升级?
redis这样设计可以节省内存的使用,只有需要的时候才会去重新分配更多的内存,提高了内存的使用效率。
降级
redis不支持降级,当整数类型升级后不可以降级。比如整数集合只有一个类型为int32_t的元素,其他的元素用int16_t类型就可以存储,此时将该元素删除后,整数集合并不会降级为int16_t,而还是维持int32_t类型的。
注意点
- 整数集合底层是用数组存储的,所以添加和移除的时间复杂度为O(n)
- 整数集合底层存储是有序的,所以查找操作可以用二分查找,时间复杂度为O(log^N^)
参考:
- Redis设计与实现. 黄健宏著.
- Redis中的整数集合
- redis 整数集合
- redis:整数集合
- redis-整数集合
- redis数据结构之整数集合
- Redis 学习 ---- 6.整数集合
- redis之六整数集合
- Redis-数据结构-5-整数集合
- Redis-数据结构-整数集合-intset
- Redis源码剖析--整数集合
- Redis源码剖析--整数集合
- Redis源码解析:06整数集合
- Redis源码剖析--整数集合Intset
- redis inset整数集合的源码分析
- redis源码学习之整数集合
- redis设计与实现(六)整数集合
- Redis源码分析(四)——Redis数据结构-整数集合
- Redis内部数据结构详解之整数集合(intset)
- Linux Platform devices 平台设备驱动
- MySQL如何添加外键
- 模态窗口
- Maven构建聚合项目
- C#实例化一个对象的方法
- redis-整数集合
- 18. 4Sum
- 1. 线性结构--线性表
- 设计模式之装饰模式
- jsonp跨域请求
- 基于Qt的软件框架设计
- 分类模型的评估方法-正确率(Accuracy)
- 0. 基本概念
- python的xlrd&xlwt