一、整数集合的底层实现
当集合中的元素都是整数值,并且元素的数量不多时,redis会使用整数集合作为集合键的底层实现。
typedef struct intset {
// 编码方式
uint32_t encoding;
// 集合中的元素数量
uint32_t length;
// 保存元素的数组
int8_t contents[];
} intset;- encoding:encoding属性的值可为INTSET_ENC_INT16、INTSET_ENC_INT32、INTSET_ENC_INT64
- length:集合中元素的数量,即contents数组的长度
- contents:集合中的每个元素是数组中的一项,并且按照从小到大依次排序,没有任何重复项;虽然contents声明为int8_t类型的数组,实际上数组的类型根据encoding的编码方式而定。
二、升级操作
当集合中添加一个新元素时,新元素的类型大小比当前集合中所有元素的类型都要大时,就需要先进行升级操作,才能将这个元素添加到集合中。升级的步骤如下:
- 根据新元素的大小和元素的数量重新分配内存空间
- 将现有集合中的元素放到正确的位置,保持有序性不变
- 将新元素添加到新集合最后一个位置或第一个位置
三、升级的好处
- 灵活性:因为c语言是静态类型的语言,所以整数数组中不能将不同类型的元素放在同一个集合中;所以有了自动升级操作,我们可以放心的将不同类型的元素放在同一个集合中
- 节约内存:自动升级可以节约内存,根据实际情况逐步扩展所需的内存,而不用一开始都声明为int64类型的数组。
四、降级
整数集合不能进行降级操作,一旦对数组进行了升级,编码方式就一直保持为升级后的状态。
五、API
函数 | 作用 | 时间复杂度 |
intsetNew | 创建一个新的整数集合 | O(1) |
intsetAdd | 添加一个新元素 | O(n) |
intsetRemove | 从集合中移除指定元素 | O(n) |
intsetFind | 指定元素是否在集合中 | O(logN)二分查找 |
intsetRandom | 从集合中随机返回一个元素 | O(1) |
intsetGet | 获得给定索引上的元素 | O(1) |
intsetLen | 获得集合的长度 | O(1) |
intsetBlobLen | 获得集合所占的内存字节数 | O(1) |