Redis整数集合
Redis的整数集合(intset )不是基础的数据结构,而是Redis自身设计的存储结构,是集合密钥的基础实现之一。 中只包含整数值要素,该集合的要素数少时,Redis将整数集合作为集合密钥的基础安装使用。
整数集合实现
整数集合(intset )是Redis用于保存整数值的集合抽象数据结构,它保存int16_t、int32_t或int64_t类型的整数值,并保证集合中没有重复元素。 结构定义如下://各intset结构表示整数的集合
类型结构插入
//编码方式
uint 32 _ t编码;
//集合中包含的元素数
unt 32长度;
//保存元素数组
int8 _ t内容[ ];
(}插入; contents数组是整数集合的基本实现。 整数集合中的每个元素都是contents数组的单个数组条目(item ),每个条目在数组中根据值的大小按从小到大的顺序排列,数组中不包含重复的条目。
length属性记录数组的长度。
虽然intset结构将contents属性声明为int8_t类型的数组,但实际上contents数组不会保存int8_t类型的值,而contents数组的真正类型取决于encoding属性的值。 如果encoding属性的值为INTSET_ENC_INT16,则数组为uint16_t类型,数组的各元素为int16_t类型的整数值(-32768——32767 ),而encoding属性为
结构如下图所示。
上图为int16_t型整数的集合。 可以看到数组中存储有5个int16_t型整数,按从小到大的顺序排列。 这个时候我们会考虑一个问题。 此时,如果加入int32_t型的整数会怎么样? 内存溢出? 此时,要提到整数集合的升级。
整数集合的升级
升级过程
如上所述,每次将新元素添加到整数集合时,如果新元素的类型比整数集合中的所有现有元素的类型都长,则必须在将整数集合添加到整数集合之前进行升级。 要升级整数集合并添加新元素,主要需要执行三个步骤。根据新元素的类型,将扩展整数集合的基数组的空间大小,并为新元素分配空间。 将基数组中的所有现有元素转换为与新元素相同的类型,并将类型转换后的元素放置在正确的位中。 此外,在放置元素时,还必须继续维持基数组的有序性质。 将新元素添加到下面的数组中。
整数集合升级的优点
提升灵活性
语言是静态语言,因此为了避免类型错误,通常不会将两种不同的值放入同一数据结构中。例如,通常只使用int16_t类型的数组来保存int16_t类型的值,而只使用int32_t类型的数组来保存int32_t类型的值。 但是,整数集合可以通过自动升级基数组来适应新元素,因此可以自由地将int16_t、int32_t或int64_t类型的整数添加到集合中。 不用担心类型错误。 这个方法非常灵活。
节约内存
要想在一个数组中同时存储int16_t、int32_t、int64_t三种类型的值,最简单的方法是直接将int64_t类型的数组作为整数集合的基础进行实现。 但是,即使添加到整数集合的值都是int16_t型或int32_t型,数组也需要使用int64_t型的区域来存储它们,有时会浪费存储器。整数集合的当前方法现在允许集合同时存储三种不同类型的值,并且只在需要时执行升级操作。 这样可以最大限度地减少内存。 如果只向整数集合添加in
t16_t 类型的值,那么整数集合的底层实现就会一直是 int16_t 类型的数组,只有在我们要将 int32_t 类型或者 int64_t 类型的值添加到集合时,程序才会对数组进行升级。降级
整数集合不支持降级操作,一旦对数组进行了升级,编码就会一直保持升级后的状态。也就是说一旦我们向一个 int16_t 的整数集合内添加了一个 int32_t 的元素后,整数集合将升级到 int32_t 类型。即使后续的操作中我们删除了这个元素,整数集合还是会保持 int32_t 类型的状态。
整数集合常用操作时间复杂度
操作
时间复杂度
创建一个新的整数集合
O(1)
添加指定元素到集合
O(N)
移除指定元素
O(N)
判断指定元素是否在集合中
O(logN)
随机返回一个元素
O(1)
取出在指定索引上的元素
O(1)
返回集合包含的元素个数
O(1)
返回集合占用的内存字节数
O(1)