Redis设计与实现之跳跃表

news2024/10/6 6:45:51

目录

一、跳跃表

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) 3

redis>ZRANGE s 0-1WITHSCORES

1)"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.coloradmin.cn/o/1314402.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用React实现随机颜色选择器,JS如何生成随机颜色

背景 在标签功能中,由于有「背景色」属性,每次新增标签时都为选择哪种颜色犯难。因此,我们思考如何通过JS代码生成随机颜色,提取一个通用的随机颜色生成工具,并基于React框架封装随机颜色选择器组件。 实际效果 原理…

智能插座是什么

智能插座 电工电气百科 文章目录 智能插座前言一、智能插座是什么二、智能插座的类别三、智能插座的原理总结 前言 智能插座的应用广泛,可以用于智能家居系统中的电器控制,也可以应用在办公室、商业场所和工业控制中,方便快捷地实现电器的远…

Python:如何将MCD12Q1\MOD11A2\MOD13A2原始数据集批量输出为TIFF文件(镶嵌/重投影/)?

博客已同步微信公众号:GIS茄子;若博客出现纰漏或有更多问题交流欢迎关注GIS茄子,或者邮箱联系(推荐-见主页). 00 前言 之前一段时间一直使用ENVI IDL处理遥感数据,但是确实对于一些比较新鲜的东西IDL并没有python那么好的及时性&…

【STM32独立看门狗(IWDG) 】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、看门狗是什么?1.简介2. 主要功能3.独立看门狗如何工作4.寄存器写保护5.看门狗 看门时间 二、使用步骤1.开启时钟2.初始化看门狗3.开启看门狗4.喂…

Knife4j 接口文档如何设置 Authorization 鉴权参数?

🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🌺 仓库主页: Gitee 💫 Github 💫 GitCode 💖 欢迎点赞…

用23种设计模式打造一个cocos creator的游戏框架----(十一)桥接模式

1、模式标准 模式名称:桥接模式 模式分类:结构型 模式意图:将抽象部分与其实现部分分离,使它们都可以独立地变化。 结构图: 适用于: 1、不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如&am…

高并发如何实现单用户信息查询接口

高并发如何实现单用户信息查询接口 故事情节 产品:小李,有个单用户信息查询的功能,需要你实现一下小李:这还不简单,两分钟我给你实现两分钟过去…小李:欧克了,部署上线了运维:哪个…

Nessus漏洞扫描报错:42873 - SSL Medium Strength Cipher Suites Supported (SWEET32)

个人搭建的windows server 2019服务器,被Nessus工具扫描出现三个漏洞,修复比较过程比较坎坷,特记录下 首先:报错信息: 42873 - SSL Medium Strength Cipher Suites Supported (SWEET32) 104743 - TLS Version 1.0 Protocol Detection 157288 - TLS Version 1.1 Protocol …

网络互通--三层交换机配置

目录 一、三层交换机的原理 1、概念 2、PC A与不同网段的PC B第一次数据转发过程 3、一次路由,多次转发的概念 4、 三层交换机和路由器的比较 二、利用实验理解交换机 1、建立以下拓扑图​编辑 2、分别配置主机的IP地址,子网掩码、网关等信息 3、…

自然语言处理阅读第一弹

Transformer架构 encoder和decoder区别 Embeddings from Language Model (ELMO) 一种基于上下文的预训练模型,用于生成具有语境的词向量。原理讲解ELMO中的几个问题 Bidirectional Encoder Representations from Transformers (BERT) BERT就是原生transformer中的Encoder两…

用23种设计模式打造一个cocos creator的游戏框架----(十七)命令模式

1、模式标准 模式名称:命令模式 模式分类:行为型 模式意图:将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤销的操作。 结构图: 适用于&am…

2024年20多个最有创意的AI人工智能点子

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情 探索 2024 年将打造的 20 个基于人工智能产品的盈利创意 🔥🔥🔥 直到最近,企业对人工智能还不感兴趣,但…

基于C/C++的libcurl多协议文件传输库dll二次封装开发使用

libcurl 可能是最便携、最强大和最常用的 这个星球上的网络传输库。官方提供的示例,需要在项目中引用到libcurl-imp.lib才能使用。 这里我改造了下工程,将常用的接口导出到了libcurl.dll中方便直接在后续的工程代码中应用,下面可以看到dll常用…

使用广播星历进行 GPS 卫星位置的计算

目录 1.计算卫星运动的平均角速度 n 2.计算观测瞬间卫星的近地点角 3.计算偏近点角 4.计算真近点角 f 5.计算升交角距 6.计算摄动改正项 7.进行摄动改正 8.计算卫星在轨道面坐标系中的位置 9.计算观测瞬间升交点的经度 L 10.计算卫星在瞬时地球坐标系中的位置 11.…

最大子数组和java实现【动态规划基础练习】

12.15 最大子数组和 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。 示例 1: 输入:nums [-2,1,-3,4,-1,2,1,-5,4]…

笔记本电脑如何安装爱快软路由

环境: dell3490 笔记本 装机U盘 问题描述: 笔记本电脑如何安装爱快软路由 解决方案: 1.电脑bios关闭 安全启动 2.下载官网镜像 3.UEFI引导 在PE下面 新建esp分区300M 把系统镜像里面全部文件,提取到这个分区 最后&…

数据结构(7.5)-- 树扩展之字典树

一、字典树 1、字典树介绍 字典树,也称为“前缀树”,是一种特殊的树状数据结构,对于解决字符串相关问题非常有效。典型 用于统计、排序、和保存大量字符串。所以经常被搜索引擎系统用于文本词频统计。它的优点是: 利用字符串的…

【Qt问题记录】使用QDebug类输出不带转义或双引号

问题 使用Qt进行编程时,需要借助输出信息验证编码的正确性。 默认情况下,如果输出的是字符串,qDebug() 会在字符串的两侧加上引号,有时还会转义。 如下所示: QString strInfo QStringLiteral("helloworld"…

[原创][R语言]股票分析实战:周级别涨幅趋势的相关性

[简介]常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、De…

网络安全Web学习记录———CTF---Web---SQL注入(GET和POST传参)例题

小白初见,若有问题,希望各位大哥多多指正~ 我的第一道web类CTF题——一起来撸猫o(•ェ•)m-CSDN博客 最开始学习CTF里的web方向时,每次做了题遇到类似的老是忘记之前的解法,所以写点东西记录一下。听大哥的话,就从最…