Redis面试题分享九:Redis 的跳跃表是怎么实现的?

目录

一、跳跃表简介

二、什么是跳跃表(skiplist)

三、跳跃表的底层结构


一、跳跃表简介

 跳跃表(skiplist)是一种随机化的数据结构,由 William Pugh 在论文《Skip lists: a probabilistic alternative to balanced trees》中提出,是一种可以于平衡树媲美的层次化链表结构——查找、删除、添加等操作都可以在对数期望时间下完成;

我们在上一篇中提到了 Redis 的五种基本结构中,有一个叫做 有序列表 zset 的数据结构,它类似于 Java 中的 SortedSet 和 HashMap 的结合体,一方面它是一个 set 保证了内部 value 的唯一性,另一方面又可以给每个 value 赋予一个排序的权重值 score,来达到 排序 的目的。

它的内部实现就依赖了一种叫做 「跳跃列表」 的数据结构。

为什么使用跳跃表

首先,因为 zset 要支持随机的插入和删除,所以它 不宜使用数组来实现,关于排序问题,我们也很容易就想到 红黑树/ 平衡树 这样的树形结构,为什么 Redis 不使用这样一些结构呢?

  1. 性能考虑: 在高并发的情况下,树形结构需要执行一些类似于 rebalance 这样的可能涉及整棵树的操作,相对来说跳跃表的变化只涉及局部 (下面详细说)
  2. 实现考虑: 在复杂度与红黑树相同的情况下,跳跃表实现起来更简单,看起来也更加直观;

基于以上的一些考虑,Redis 基于 William Pugh 的论文做出一些改进后采用了 跳跃表 这样的结构。

二、什么是跳跃表(skiplist)

跳跃表(Skip List)是一种基于链表的数据结构,它可以实现诸如有序集合(Sorted Set)等数据结构,能够提供平均 O(log n) 的查找效率。Redis中就使用跳跃表来实现有序集合。

跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其它节点的指针,从而达到快速访问节点的目的。和链表、字典等数据结构被广泛地应用在 Redis 内部不同,Redis 只在两个地方用到了跳跃表,一个是实现有序集合健,另一个是在集群节点中用做内部数据结构,除此之外,跳跃表在 Redis 里没有其它用途。

我们来想一下,为啥 Redis 中这两个场景要选择 skiplist?

既然跳跃表是一种有序数据结构,那我们就来考虑在有序序列中查找某个特定元素的情境:

  • 如果该序列用支持随机访问的线性结构(数组)存储,那么我们很容易地用二分查找来做。

  • 但是考虑到增删效率和内存扩展性,很多时候要用不支持随机访问的线性结构(链表)存储,就只能从头遍历、逐个比对。

  • 作为折衷,如果用二叉树结构(BST)存储,就可以不靠随机访问特性进行二分查找了。

三、跳跃表的底层结构

Redis 的跳跃表是由 redis.h/zskiplistNode 和 redis.h/zskiplist 两个结构定义,其中 zskiplistNode 用于表示跳跃节点,而 zskiplist 结构则用于保存跳跃表节点的相关信息,比如节点的数量以及指向表头节点和表尾节点的指针等等。


上图最左边的是 zskiplist 结构,该结构包含以下属性:

  • header:指向跳跃表的表头节点

  • tail:指向跳跃表的表尾节点

  • level:记录目前跳跃表内,层数最大的那个节点层数(表头节点的层数不计算在内)

  • length:记录跳跃表的长度,也就是跳跃表目前包含节点的数量(表头节点不计算在内)

位于 zskiplist 结构右侧是四个 zskiplistNode 结构,该结构包含以下属性:

  • 层(level):节点中用 L1、L2、L3 等字样标记节点的各个层,L1 代表第一层,L2 代表第二层,以此类推。每个层都带有两个属性:前进指针和跨度。前进指针用于访问位于表尾方向的其它节点,而跨度则记录了前进指针所指向节点和当前节点的距离。

  • 后退(backward)指针:节点中用 BW 字样标识节点的后退指针,它指向位于当前节点的前一个节点。后退指针在程序从表尾向表头遍历时使用。

  • 分值(score):各个节点中的 1.0、2.0 和 3.0 是节点所保存的分值。在跳跃表中,节点按各自所保存的分值从小到大排列。

  • 成员对象(obj):各个节点中的 o1、o2 和 o3 是节点所保存的成员对象。

我们接下来看下 Redis 是如何实现 skiplist 的。

结构定义

zskiplist 的结构定义:

zskiplistNode 的结构定义:

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之乎者也·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值