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。

相关推荐
爱的叹息25 分钟前
Spring Boot 集成 Redis中@Cacheable 和 @CachePut 的详细对比,涵盖功能、执行流程、适用场景、参数配置及代码示例
spring boot·redis·后端
一期一祈^26 分钟前
使用MySQL时出现 Ignoring query to other database 错误
数据库·mysql
Mr.wangh1 小时前
Spring Boot 打印日志
java·数据库·spring boot
勤劳的进取家1 小时前
贪心算法之Huffman编码
数据结构·人工智能·算法·数学建模·贪心算法·动态规划
BenBen尔1 小时前
innodb如何实现mvcc的
数据库
孪生质数-2 小时前
2-Visual Studio 2022 NET开发Windows桌面软件并连接SQL Server数据库
数据库·windows·sqlserver·visual studio
扫地的小何尚3 小时前
使用NVIDIA NIM微服务加速科学文献综述
开发语言·数据结构·人工智能·深度学习·微服务·云原生·架构
T0uken3 小时前
【LLM】MCP(Python):实现 SSE 通信的 Server 和 Client
数据库·python·microsoft
代码AC不AC3 小时前
【数据结构】树的介绍
c语言·数据结构··学习分享·技术交流
Demons_kirit4 小时前
LeetCode 1863.找出所有子集的异或总和再求和
数据结构·算法·leetcode