Redis设计与实现之跳跃表

目录

一、跳跃表

1、跳跃表的实现

2、跳跃表的应用

3、跳跃表的时间复杂度是什么?

二、跳跃表有哪些应用场景?

三、跳跃表和其他数据结构(如数组、链表等)相比有什么优点和缺点?

四、Redis的跳跃表支持并发操作吗?如何保证并发安全?

五、跳跃表的大小和内存占用是如何计算的?

六、Redis的跳跃表有没有限制元素数量的上限?

七、跳跃表的迭代器是如何实现的?

八、Redis的跳跃表和其他数据库(如MySQL、MongoDB等)的索引结构有何不同?

九、小结


一、跳跃表

跳跃表(skiplist)是一种随机化的数据,由 William Pugh 在论文《Skip lists: a probabilistic alternative to balanced trees》中提出,这种数据结构以有序的方式在层次化的链表中保存元 素,它的效率可以和平衡树媲美——查找、删除、添加等操作都可以在对数期望时间下完成, 并且比起平衡树来说,跳跃表的实现要简单直观得多。

以下是一个典型的跳跃表例子:

从图中可以看到,跳跃表主要由以下部分构成: 

•表头( head) :负责维护跳跃表的节点指针。

•跳跃表节点:保存着元素值,以及多个层。

•层:保存着指向其他元素的指针。高层的指针越过的元素数量大于等于低层的指针,为了提高查找的效率,程序总是从高层先开始访问,然后随着元素值范围的缩小,慢慢降低层次。

•表尾:全部由 NULL组成,表示跳跃表的末尾。

因为跳跃表的定义可以在任何一本算法或数据结构的书中找到,所以本章不介绍跳跃表的具体

实现方式或者具体的算法,而只介绍跳跃表在 Redis的应用、核心数据结构和 API。

1、跳跃表的实现

为了适应自身的功能需要, Redis基于 William Pugh 论文中描述的跳跃表进行了以下修改:

1.允许重复的 score值:多个不同的 member的score值可以相同。

2.进行对比操作时,不仅要检查 score值,还要检查 member:当score值可以重复时,单靠score值无法判断一个元素的身份,所以需要连 member域都一并检查才行。

3.每个节点都带有一个高度为 1层的后退指针,用于从表尾方向向表头方向迭代:当执行ZREVRANGE 或 ZREVRANGEBYSCORE 这类以逆序处理有序集的命令时,就会用到这个属性。

这个修改版的跳跃表由 redis.h/zskiplist 结构定义:

typedef structzskiplist {//头节点,尾节点structzskiplistNode *header, *tail;//节点数量unsigned longlength;//目前表内节点的最大层数intlevel;} zskiplist;

跳跃表的节点由 redis.h/zskiplistNode 定义:

typedef structzskiplistNode {// member 对象robj*obj;//分值doublescore;//后退指针structzskiplistNode *backward;//层structzskiplistLevel {//前进指针structzskiplistNode *forward;//这个层跨越的节点数量unsigned intspan;} level[];} zskiplistNode;

以下是操作这两个数据结构的 API,它们的作用以及相应的算法复杂度:

2、跳跃表的应用

和字典、链表或者字符串这几种在 Redis中大量使用的数据结构不同,跳跃表在 Redis的唯一作用,就是实现有序集数据类型。

跳跃表将指向有序集的 score值和member域的指针作为元素,并以 score值为索引,对有序集元素进行排序。

举个例子,以下代码就创建了一个带有 3个元素的有序集:

redis>ZADD s6x10y15z(integer) 3redis>ZRANGE s 0-1WITHSCORES1)"x"2)"6"3)"y"4)"10"5)"z"6)"15"

在底层实现中, Redis为x、y和z三个member分别创建了三个字符串,并为 6、10和15分别创建三个 double类型的值,然后用一个跳跃表将这些指针有序地保存起来,形成这样一个跳跃表:

为了展示的方便,在图片中我们直接将 member和score值包含在表节点中,但是在实际的定义中,因为跳跃表要和另一个实现有序集的结构(字典)分享 member和score值,所以跳跃表只保存指向 member和score的指针。

3、跳跃表的时间复杂度是什么?

跳跃表(Skip List)是一种数据结构,用于实现有序的集合数据。对于搜索、插入和删除操作,跳跃表的时间复杂度为O(log n),其中n是跳跃表中元素的数量。这是因为跳跃表通过层级索引的方式加速搜索的速度,使得每次搜索都能减少一半的搜索范围,从而使得时间复杂度保持在O(log n)。

二、跳跃表有哪些应用场景?

Redis跳跃表(Skip List)是一种有序数据结构,它通过使用多级索引来加快对元素的查找速度。它在Redis中的应用场景有:

  1. 有序集合:Redis的有序集合数据类型就是使用跳跃表来实现的。跳跃表能够保持集合元素的有序性,并且支持高效地插入、删除和查找操作。

  2. 排行榜:跳跃表可以用于实现排行榜功能,可以根据某个指标对用户进行排名,并且支持快速的插入和删除操作。

  3. 范围查询:跳跃表可以快速地查找某个范围内的元素,例如在一个有序集合中查找某个分数范围内的成员。

  4. 分数计算:跳跃表可以用于对成绩、评分等进行计算和排名。在Redis中,有序集合的元素可以关联一个分数,可以通过跳跃表来快速进行分数计算和排名。

  5. 事件排序:跳跃表可以用于对时间事件进行排序和管理,例如定时任务管理器、事件调度器等。

总的来说,Redis跳跃表适用于需要高效地进行元素排序、查找和范围查询的场景。它的优势在于简单、高效,适用于有序集合等需要有序性的场景。

三、跳跃表和其他数据结构(如数组、链表等)相比有什么优点和缺点?

Redis跳跃表相对于其他数据结构(如数组、链表等)具有以下优点和缺点:

优点:

  1. 快速查找:跳跃表通过索引层级的方式实现了快速查找,其时间复杂度为O(logn),比数组和链表的线性查找效率更高。
  2. 低延迟:由于跳跃表的查找和插入操作的时间复杂度都是O(logn),不随数据量的增长而增加,因此能够保持低延迟的性能。
  3. 支持有序集合:跳跃表能够自然有序地存储数据,因此非常适合实现有序集合等需要有序存储的数据结构。
  4. 空间效率高:跳跃表的索引层级结构为每个节点增加了额外的空间开销,但相对于数组和链表来说,其空间利用率更高,可以节省存储空间。

缺点:

  1. 复杂实现:相对于数组和链表等简单的数据结构来说,跳跃表的实现较为复杂,需要维护索引层级结构,并且需要考虑各节点之间的维护和调整操作。
  2. 内存占用:跳跃表的索引层级结构需要额外的空间来存储索引节点,因此会占用较多的内存空间。
  3. 不适合频繁的插入和删除操作:跳跃表的插入和删除操作需要对索引层级进行调整和维护,对于频繁进行这些操作的场景来说,性能可能较差。

四、Redis的跳跃表支持并发操作吗?如何保证并发安全?

Redis的跳跃表(Skip List)本身并不支持并发操作,因为跳跃表的插入、删除和查找操作都需要涉及到修改指针的过程,这样会存在并发安全问题。

为了保证并发安全性,Redis使用了一种叫做"多个跳跃表"的数据结构来实现有序集合(Sorted Set)。在每个有序集合中,Redis维护了一个正常的有序跳跃表,同时还维护了一个用于支持并发的层级跳跃表。

  • 正常的有序跳跃表:用于执行读操作,每个线程可以拥有自己的迭代器去遍历跳跃表。

  • 层级跳跃表:用于执行写操作,避免并发写入过程中对同一个节点进行修改。在更新节点时,首先会在层级跳跃表上进行更新,然后再更新到正常的有序跳跃表上。

通过这种方式,Redis实现了有序集合的并发操作,保证了并发安全性。

五、跳跃表的大小和内存占用是如何计算的?

Redis跳跃表(Skip List)是一种有序数据结构,用于实现有序集合键(Sorted Set Key)。跳跃表通过将数据分层,从而实现快速查找、插入和删除操作。

Redis跳跃表的大小取决于其中存储的键值对数量。每个节点包含一个或多个层级,每个层级维护了指向下一层级的指针。节点的数量和层级的大小都会影响跳跃表的大小。具体而言,跳跃表的大小可以通过以下公式计算:

Size = N * (entry size) + M * (pointer size)

其中,N表示跳跃表中的节点数量,entry size表示每个节点的键值对大小,M表示指针的数量,pointer size表示每个指针的大小。

跳跃表的内存占用主要取决于两个因素:节点数量和层级大小。节点数量较多会占用更多内存,而层级大小决定了每个节点的指针数量。因为指针通常比键值对更小,所以较大的层级大小可以节省内存。然而,较大的层级大小也会增加跳跃表的高度,可能增加查找操作的时间复杂度。

需要注意的是,Redis在使用跳跃表之前会使用普通的链表实现有序集合键。当数据量较小时,Redis会使用链表,当数据量超过一定阈值时,才会转换为跳跃表。因此,实际内存占用可能受到数据量和跳跃表与链表使用比例的影响。

六、Redis的跳跃表有没有限制元素数量的上限?

Redis的跳跃表(Skip List)没有固定的元素数量上限限制。每个跳跃表节点都可以包含多个元素,而每个节点的高度也是动态调整的,因此跳跃表可以根据需要动态地增长和缩小。跳跃表的高度可以通过调整概率来控制,从而控制跳跃表的大小。因此,Redis的跳跃表可以容纳非常大数量的元素。

七、跳跃表的迭代器是如何实现的?

Redis中的跳跃表(skiplist)是一种有序的数据结构,它通过多级索引来加速查询操作的效率。跳跃表的迭代器用于遍历跳跃表中的元素。

跳跃表的迭代器是通过指针和索引操作实现的。迭代器是一个可迭代对象,它在每次调用next()方法时返回下一个元素。迭代器可以在跳跃表中向前或向后遍历元素。

具体实现步骤如下:

  1. 创建一个迭代器对象,并初始化为跳跃表的头节点(或尾节点)。
  2. 在迭代器对象中,有一个指针指向当前节点。通过这个指针,可以访问当前节点的元素和索引。
  3. 通过指针和索引操作,可以实现在跳跃表中向前或向后遍历。例如,通过指针可以直接访问当前节点的下一个节点,从而实现向前或向后遍历。
  4. 在每次调用next()方法时,迭代器将返回当前节点的元素,并将指针指向下一个节点。
  5. 如果跳跃表中没有下一个节点,则迭代器将返回结束标记,表示遍历已经完成。

需要注意的是,当跳跃表中的元素被删除或添加时,迭代器可能会失效。为了保证迭代器的正确性,可以使用版本号或者加锁机制。

总而言之,Redis中的跳跃表迭代器通过指针和索引操作来遍历跳跃表中的元素,可以向前或向后遍历,并在每次调用next()方法时返回当前节点的元素。

八、Redis的跳跃表和其他数据库(如MySQL、MongoDB等)的索引结构有何不同?

Redis的跳跃表(skiplist)是一种有序数据结构,用于实现有序集合(Sorted Set)的索引。它通过多层级的有序链表来快速查找元素,具有类似于平衡二叉树的效率。

与其他数据库的索引结构相比,Redis的跳跃表有以下特点:

  1. 简单高效:跳跃表的实现相对简单,插入、删除和查找操作的时间复杂度都是O(log N),并且具有较低的常数系数。相比之下,其他数据库的索引结构如B树或哈希索引的复杂性更高。

  2. 内存友好:跳跃表存储在内存中,不需要进行磁盘读写操作,因此具有更低的延迟和更高的吞吐量。而其他数据库的索引结构如B树则需要频繁地读写磁盘。

  3. 有序性:跳跃表可以保持元素的有序性,并支持范围查询操作,如获取区间内的元素。

相比之下,其他数据库的索引结构如B树或哈希索引可能不具备这些特点。例如,B树需要进行平衡操作以维持树的平衡性,而哈希索引则无法提供范围查询操作。因此,Redis的跳跃表在某些场景下可以更加高效和灵活地满足需求。

九、小结

•跳跃表是一种随机化数据结构,它的查找、添加、删除操作都可以在对数期望时间下完成。

•跳跃表目前在 Redis的唯一作用就是作为有序集类型的底层数据结构(之一,另一个构

成有序集的结构是字典) 。

•为了适应自身的需求, Redis基于 William Pugh 论文中描述的跳跃表进行了修改,包括:

1.score值可重复。

2.对比一个元素需要同时检查它的 score和memeber 。

3.每个节点带有高度为 1层的后退指针,用于从表尾方向向表头方向迭代。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/278505.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode:2415. 反转二叉树的奇数层(层次遍历 Java)

目录 2415. 反转二叉树的奇数层 题目描述: 实现代码与解析: BFS 原理思路: 2415. 反转二叉树的奇数层 题目描述: 给你一棵 完美 二叉树的根节点 root ,请你反转这棵树中每个 奇数 层的节点值。 例如,…

【单调栈]LeetCode84: 柱状图中最大的矩形

作者推荐 【动态规划】【广度优先搜索】LeetCode:2617 网格图中最少访问的格子数 本文涉及的知识点 单调栈 题目 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形…

动态规划——斐波那契数列模型:1137.第N个泰波那契数

文章目录 题目描述算法原理1.状态表示(最重要的)什么是状态表示?状态表示怎么来的呢?本题的状态表示 2.状态转移方程(最难的)本题的状态转移方程 3.初始化(后三步完成剩下百分之一的细节问题)本题的初始化 4.填表顺序本…

怎样下载微博视频而不至于发生“403 Forbidden“现象?

近段时间不知道从什么时候开始,微博视频都不让从网页下载了。以前是看到有想要下载的微博视频,就点进去微博详情页用谷歌浏览器F12进入调试的方式,选“Network”->“Media”->重新F5刷新页面等待调试框里出现链接->在链接上鼠标右键…

MyBatis环境的搭建

1.创建 Maven 工程 打开idea新建一个项目File → Project Structure → Project,build system中选择maven (1)由于 IDEA 中集成了 Maven,所以我们就不需要下载了,直接使用 IDEA 默认的 Maven 进行项目构建。 &#…

笔记本电脑如何安装openwrt

环境: 联想E14笔记本 装机U盘 DiskImage v1.6 刷写工具 immortalwrt镜像 问题描述: 笔记本电脑如何安装openwrt 解决方案: 一、官方版 1.官网下载固件 2.BIOS关闭安全启动改为引导 3.用U盘启动进入PE系统后,需要先用PE系…

数据结构(七):树介绍及面试常考算法

一、树介绍 1、定义 树形结构是一种层级式的数据结构,由顶点(节点)和连接它们的边组成。 树类似于图,但区分树和图的重要特征是树中不存在环路。树有以下特点: (1)每个节点有零个或多个子节点…

三种好用的在线色彩提取工具

#三种好用的在线色彩提取工具 1.ecjson网站 网址: https://www.ecjson.com/image_color#b1cfea 或点击链接: ecjson在线色彩提取 图1 ecjson网站色彩提取举例 2.微查网 网址:http://zxqsq.wiicha.com/ 或点击链接: 微查网在线色彩提取 …

企业微信旧版-新版网络连接错误,无法登录的解决方案

一.企业微微信无法登录故障 二.解决方案 1.网上的解决方案 **检查网络连接:**确保你的计算机正常连接到互联网。尝试打开其他网页,以确保网络连接正常。 **防火墙和安全软件:**某些防火墙或安全软件可能会阻止企业微信的正常连接。请确保你…

【Axure RP9】的详细安装及Axure入门应用

目录 一 Axure入门安装 1.1 Axure是什么? 1.2 Axure应用场景 1.3 Axure安装 1.3.1 汉化 1.3.2 授权 二, Axure应用 1.1 Axure软件界面概述 1.2 Axure的应用 1.2.1备份 1.2.2 视图显示及网格设置 1.2.3 生成HTML文件 1.2.4 备注说明 一 Axure入门安装 1.1 Axure…

使用blip2进行图片输入文本输出

多模态的重要模型blip2,官方提供模型可以直接用来图片生成文本 github地址:https://github.com/salesforce/LAVIS/tree/main/projects/blip2 个人相当于跑了一下blip2的demo,记录下过程,供今后需要参考: 1、首先是环境安装&#…

Tableau快速入门-下载安装加载数据与仪表盘构建

官网介绍 官网连接如下: https://www.tableau.com/zh-cn tableau的产品包括如下: 参考:https://zhuanlan.zhihu.com/p/341882097 Tableau是功能强大、灵活且安全些很高的端到端的数据分析平台,它提供了从数据准备、连接、分析、协作到查阅…