Redis 中 IntSet 底层数据结构

IntSet 底层数据结构

序言:

像字符串 SDS 只是保存了一个变量的值,但是像 Redis 中也是需要保存一些集合元素的,这里就介绍一下其中一种集合 IntSet,由于是 Set 所以也有 Set 的一些特性,不过也多加了一些特性:

● 唯一

● 长度可变

● 有序

● 可自动升级

数据结构

这里先来看一下 InSet 的底层结构:

contents数组 :用来保存元素的,用的就是 C 语言里面的数组,不过可以观察到这个数组的类型是 int8_t 就说明这个数组能够存的数字很小(-128~127)。难道这个 IntSet 的数据结构就只能存这些数字吗,其实并不是的,它到底存哪些数字主要由 InSet 的 encoding 字段来控制的,它本身算是充当一个数组的起始地址。
length :表示元素的个数。
encoding :编码方式,支持三种编码方式,这三种方式用来表示存储在数组中的数据能够表示多大,且每一个数字读取的方式和占用数组的大小也不一样。

这里以 16 位来举例:

比如存放一个 16 位能够表示的数字,那么单独放在 8 位的数组中是放不下的,所以在 contents 数组中会以两位来表示一个数字,那么读取的时候也是两位一起读然后转换成一个数字,所以说其实 contents 这个字段充当的是一个数组的起始地址,但是往里面存怎么样的数字和怎么读取都是由 IntSet 来控制的,可以利用多位来表示一个数组。

所以在 IntSet 中读取元素的方式也是有一个计算公式的。

bash 复制代码
startPtr + (sizeof(encoding) * index)

这个公式的具体含义就是,从数组起始地址开始 加上 读取元素索引 * 编码大小,就表示要读到的元素的位置。

由于每种编码的方式不同导致在一个数组中可能一个数占用的大小也不相同,所以需要索引 * 编码的大小。

并且如果读到元素之后也需要同样读取编码大小相同个数的位数才能组成想要的值。

由于要确保这个计算公式的准确性,所以 Inset 中要求存在数组中的编码要统一。

接下来举个例子:

存放5、10、20三个元素。

这里这三个数都在 16 位编码内能够存储,所以采用 16 编码,由于是16位编码,所以这三个元素每个元素都占用数组中的两位,也就是两个字节。

计算一下当前 IntSet 的大小。

● encoding:4 字节

● length:4 字节

● contents:2*3=6 字节

总共是 14 字节。

保存在 IntSet 中的数据也会保持一个有序的状态,为了就是能够使用二分查找法更快的找到元素。

IntSet 自动升级

不过之前说过要求存在 contents 中的数据要求编码必须统一为了方便计算要查找的数据的位置。但是如果有一个数要存到当前数组中,但是它的数对应的编码大于当前编码会怎么办。

这里就涉及到了 IntSet 的升级,会自动把数组中的所有数对应的编码升级。

举例:

例如现在还是存 5,10,20这三个数,对应的编码也是 16 位的。

此时如果向数组中添加一个 50000 超过 16 编码,需要使用 32 位编码,这时候 IntSet 会自动升级,会按照新的编码和元素个数进行数组的扩容。

这时每个元素都需要占用 4 个字节,确保编码的一致性,所以数组需要占用的内存就是(3+1) * 4 == 16 字节

计算完数组的大小之后,就需要将原先的数组中的数据扩大到相对应的编码大小之后,倒序的拷贝到扩容后的数组中。

这里为什么需要倒叙呢?

因为如果正序的话,假设这里是5先转移,那么 5 原先占用 2 个字节,然后扩容到四个字节然后在进行拷贝,在扩容到 4 个字节的时候就会把后面 10 这个数字给覆盖掉了,就导致数据的丢失,但是如果是倒叙,从 20 开始的话,20后面没有数字可以放行的扩容然后转移。所以需要倒倒序。

当转移完成之后:

这时候就可以把新要插入的数据放入到数组的尾部。

最后要修改头信息中的 encoding 和 length。

相关推荐
数据知道5 分钟前
PostgreSQL 核心原理:系统内部的对象寻址机制(OID 对象标识符)
数据库·postgresql
历程里程碑18 分钟前
普通数组----轮转数组
java·数据结构·c++·算法·spring·leetcode·eclipse
sin_hielo19 分钟前
leetcode 1653
数据结构·算法·leetcode
李日灐22 分钟前
C++进阶必备:红黑树从 0 到 1: 手撕底层,带你搞懂平衡二叉树的平衡逻辑与黑高检验
开发语言·数据结构·c++·后端·面试·红黑树·自平衡二叉搜索树
熬夜有啥好30 分钟前
数据结构——排序与查找
数据结构
YuTaoShao30 分钟前
【LeetCode 每日一题】3634. 使数组平衡的最少移除数目——(解法二)排序 + 二分查找
数据结构·算法·leetcode
wangluoqi31 分钟前
26.2.6练习总结
数据结构·算法
Yvonne爱编码34 分钟前
链表高频 6 题精讲 | 从入门到熟练掌握链表操作
java·数据结构·链表
倔强的石头_36 分钟前
关系数据库替换用金仓:数据迁移过程中的完整性与一致性风险
数据库
Elastic 中国社区官方博客42 分钟前
使用 Groq 与 Elasticsearch 进行智能查询
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索