redis底层数据结构2——跳跃表、压缩列表、整数集合

本文深入解析Redis中的三种重要数据结构:跳跃表用于有序集合,提供高效的查找和操作;整数集合适用于存储少量整数,通过升级策略保证空间效率;压缩列表适用于存储小对象,采用前一节点长度记录节省空间,连锁更新保证遍历性能。
摘要由CSDN通过智能技术生成

跳跃表

跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。

跳跃表支持平均O(logN)、最坏O(N)复杂度的节点查找,还可以通过顺序性操作来批量处理节点。

在大部分情况下,跳跃表的效率可以和平衡树相媲美,并且因为跳跃表的实现比平衡树要来得更为简单,所以有不少程序都使用跳跃表来代替平衡树。

Redis使用跳跃表作为有序集合键的底层实现之一,如果一个有序集合包含的元素数量比较多,又或者有序集合中元素的成员(member)是比较长的字符串时,Redis就会使用跳跃表来作为有序集合键的底层实现。

和链表、字典等数据结构被广泛地应用在Redis内部不同,Redis只在两个地方用到了跳跃表,一个是实现有序集合键,另一个是集群节点中用作内部数据结构,除此之外,跳跃表在Redis里面没有其他用途。

结构

在这里插入图片描述

  • level:记录目前跳跃表内,层数最大的那个节点的层数(表头节点的层数不计算在内)
    • 跳跃表节点的level数组可以包含多个元素,每个元素都包含一个指向其他节点的指针,程序可以通过这些层来加快访问其他节点的速度,一般来说,层的数量越多,访问其他节点的速度就越快。
    • 每次创建一个新跳跃表节点的时候,程序根据幂次定律(power law,越大的数出现的概率越小)随机生成一个介于1和32之间的值作为level数组的大小,这个大小就是层的“高度”
  • length:记录跳跃表的长度,也即是,跳跃表目前包含节点的数量(表头节点不计算在内)
  • 分数(score):各个节点中的1.0、2.0和3.0是节点所保存的分值。在跳跃表中,节点按各自所保存的分值从小到大排列。
  • 跨度:层的跨度(level[i].span属性)用于记录两个节点之间的距离

插入元素

链表的插入和删除是结合搜索过程完成的。在一个跳表中插入元素17的过程如下:
在这里插入图片描述

删除元素

删除元素1的过程如下:
在这里插入图片描述

整数集合

整数集合(intset)是集合键的底层实现之一,当一个集合中只包含整数值元素,并且这个集合的元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现。
整数集合的底层是数组,有序、无重复。

实现

结构如图所示:
在这里插入图片描述
contents 数组是整数集合的底层实现。虽然 contents 属性声明为 int8_t 类型的数组,但实际上contents数组并不保存任何 int8_t 类型的值,contents 数组的真正类型取决于 encoding 属性的值。encoding 的值可以为:INTSET_ENC_INT16、INTSET_ENC_INT32、INTSET_ENC_INT64。

升级

当加入一个新元素时,如果元素类型比集合内的所有元素类型都长,整数集合会进性升级。步骤如下:

  • 扩展空间。根据新元素的类型,扩展空间,包括新元素的空间
  • 移动旧元素。
  • 放入新元素。改编码格式。

在一个 INTSET_ENC_INT16 编码的集合中,有三个元素,现在放入65535(INTSET_ENC_INT32):
在这里插入图片描述
在这里插入图片描述

元素放入之后,要保证集合有序。
整数数组不支持降级操作。

提升灵活性

底层自动修改属性,不用担心类型错误。

节约内存

可以不用直接分配 int32 或 int64 类型的数组,有需要时才分配,避免空间浪费。

压缩列表

压缩列表(ziplist)是列表键和哈希键的底层实现之一。当一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做列表键的底层实现。
压缩列表的遍历是从表尾向表头遍历。

结构实现

在这里插入图片描述
在这里插入图片描述

  • previous_entry_length:previous_entry_length属性以字节为单位,记录了压缩列表中前一个节点的长度
    • 如果前一节点的长度小于254字节,那么previous_entry_length属性的长度为1字节
    • 如果前一节点的长度大于等于254字节,那么previous_entry_length属性的长度为5字节:其中属性的第一字节会被设置为0xFE(十进制254),而之后的四个字节则用于保存前一节点的长度。
  • encoding:节点的encoding属性记录了节点的content属性所保存数据的类型以及长度
    • 一字节、两字节或者五字节长,值的最高位为00、01或者10的是字节数组编码:这种编码表示节点的content属性保存着字节数组,数组的长度由编码除去最高两位之后的其他位记录;
    • 一字节长,值的最高位以11开头的是整数编码:这种编码表示节点的content属性保存着整数值,整数值的类型和长度由编码除去最高两位之后的其他位记录;
      在这里插入图片描述
  • content:节点的content属性负责保存节点的值,节点值可以是一个字节数组或者整数,值的类型和长度由节点的encoding属性决定

连锁更新

添加删除节点,均可能导致连锁更新。
在这里插入图片描述
在最坏的情况下,连锁更新的时间复杂度为O(n2)。但极端情况出现概率极小。平均复杂度为O(N)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值