Redis从入门到精通【高阶篇】之底层数据结构跳表(SkipList)

news2024/10/5 18:31:25

文章目录

  • 0.前言
  • 1.跳表(SkipList)基本详解
  • 2. 源码解析
  • 3.总结
  • 4.思考题
  • 5. Redis从入门到精通系列文章

在这里插入图片描述

0.前言

上个篇章回顾,我们上个章节我们学习了《Redis从入门到精通【高阶篇】之底层数据结构整数集(IntSet)详解》,我们从源码层了解整数集由一个头部和多个数据块组成。头部中存储了整数集的元素个数、编码方式和数据块的起始地址等信息。数据块中存储了实际的整型数据,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现。IntSet的设计目标是尽可能地节省内存空间,同时保证高效的操作性能。它可以存储三种类型的整数:8位整数、16位整数和32位整数。。

本章节,我们详细了解一下在Redis又一个底层数据结构跳表(SkipList),它是一种基于链表的数据结构,用于快速地插入、删除和查找元素。跳表通过多层级的指针数组来实现快速的操作,时间复杂度为O(log n),其中n为跳表中元素的个数。Redis中的有序集合(Sorted Set 也叫ZSet 它们讲的是同一个)就是通过跳表来实现的。。

1.跳表(SkipList)基本详解

跳表中的每个节点包含一个键值对,其中键用于排序元素,值用于存储具体的数据。跳表的每个节点都有多个指针,用于指向下一个节点。多个指针可以穿过一些节点,形成多层级的结构,从而实现快速的操作。

在这里插入图片描述

Redis中的有序集合(Sorted Set)使用的底层数据结构之一就是跳表(Skip List)。跳表是一种基于链表的数据结构,它通过添加多级索引来加速查找操作,从而在某些场景下可以提供比普通链表更高效的查找性能。

Redis 中zset利用跳表底层数据结构可以实现如下几个场景,这些场景可能你在其他的文章中也会提到,但是本次我们要深入的通过源码层进行解析。

  • 排行榜:跳表可以很好地支持排行榜功能,例如在游戏中记录玩家的积分排名。由于跳表在插入、删除和查找操作上的平均时间复杂度为O(log n),因此可以快速地进行排名的更新和查询。
  • 范围查询:跳表可以用于支持范围查询,例如在社交网络中按照用户的年龄范围或者地理位置范围来查找用户。跳表通过多级索引可以快速定位到指定范围的节点,从而高效地进行范围查询。
  • 实时统计:跳表可以用于实时统计数据的功能,例如统计某个时间段内的用户活跃数、订单数量等。通过跳表的插入操作,可以将数据按照时间顺序有序地存储在跳表中,并且通过多级索引可以快速定位到指定时间段的数据,从而实现实时统计的需求。

需要注意的是,跳表并不适用于所有场景,它的优势在于某些特定的读取操作,而在写入操作上相对较慢。因此,在选择使用跳表时需要根据具体的业务场景和需求来进行权衡和选择。

2. 源码解析

说了在多理论的概念和举例都略显单薄,很多同学可能在想"talk is cheap, show me code"。那么接下来我们进行一下源码解读。
在Redis的GitHub仓库中,IntSet的代码文件位于以下路径:
server.h:https://github.com/redis/redis/blob/6.0/src/server.h
t_zset.c:https://github.com/redis/redis/blob/6.0/src/t_zset.c#L90
6.0分支是Redis6的分支,包含了最新的代码修改和功能更新。所以如果有同学想详细的了解一下,也可以在该分支下找到最新的ZSkipList代码文件,如果对Redis7的源码也想了解,只需要在上面切换一下分支即可。参考代码实现来深入了解ZSkipList的数据结构和操作还是相比上节事有点复杂的。
记住这块代码的定义,我们后面的代码分析过程中会用到

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

注:如果你对C也算是了解的话,可能下面的内容就不必再看了,点击我上面的源码地址,扫一遍这两个文件基本上就一目了然。
如果你是C小白,请继续
上面截图中

server.h:细心的同学会发现,这次的源码文件为什么不是zset.h 和zeset.c了。其实这是因为在server.h文件中定义zskiplistNode结构体,是因为跳表节点它是跳表的基本组成部分,它包含了跳表中的元素值、分值等属性。作者将跳表节点的定义放在server.h文件中,可以使得其他源码文件(如src/t_zset.c)能够直接引用和操作跳表节点,方便对跳表进行插入、删除、查找等操作。

t_zset.c:t_zset.c是Redis中有序集合功能的源码文件,它包含了有序集合的各种操作的实现,如创建有序集合、插入元素、删除元素、修改元素、查询元素等。。

从上面的源码截图我们可以看出来IntSet的定义如下:

// 表示跳表中的节点的结构体
typedef struct zskiplistNode {
// 节点存储的元素值(=Redis SDS 这也是Redis的字符串的底层数据结构,简单动态字符串,如果不了解,可以看我的历史的讲解内容)
    sds ele; 
    double score; // 与元素关联的分值
    struct zskiplistNode *backward; // 指向前一个节点的指针
    struct zskiplistLevel {
        struct zskiplistNode *forward; // 指向下一个节点的指针
        unsigned long span; // 到下一个节点的跨度
    } level[]; // 灵活数组,表示节点的层级
} zskiplistNode;

// 表示整个跳表的结构体
typedef struct zskiplist {
    struct zskiplistNode *header; // 指向跳表的头节点
    struct zskiplistNode *tail; // 指向跳表的尾节点
    unsigned long length; // 跳表中节点的数量
    int level; // 跳表的最大层级
} zskiplist;

// 表示有序集合的结构体
typedef struct zset {
    dict *dict; // 使用字典实现的有序集合
    zskiplist *zsl; // 使用跳表实现的有序集合
} zset;

3.总结

在实际的Redis应用中,整数集被广泛应用于集合等数据结构的实现。通过使用整数集,Redis可以在保证高效的操作性能的同时,减少内存的浪费,提高内存利用率。可以用于存储大量的整数值,并支持快速的插入、删除和查找操作。如果您需要存储大量的整数值,可以考虑使用IntSet来优化存储空间和操作性能。

4.思考题

应一位网友的建议,在每个章节后面留个思考题,供大家继续学习。下次分享来揭晓答案。本次的思考题只有一道。
1. Redis6是如何使用IntSet来实现集合和有序集合?

5. Redis从入门到精通系列文章

《Redis从入门到精通【高阶篇】之底层数据结构字典(Dictionary)详解》
《Redis从入门到精通【高阶篇】之底层数据结构快表QuickList详解》
《Redis从入门到精通【高阶篇】之底层数据结构简单动态字符串(SDS)详解》
《Redis从入门到精通【高阶篇】之底层数据结构压缩列表(ZipList)详解》
《Redis从入门到精通【进阶篇】之数据类型Stream详解和使用示例》
在这里插入图片描述
大家好,我是冰点,今天的Redis从入门到精通【高阶篇】之底层数据结构整数集(IntSet)详解,全部内容就是这些。如果你有疑问或见解可以在评论区留言。

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

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

相关文章

Day08 Python数据结构(数据容器)详解

文章目录 第五章 Python数据容器5.1. 容器类型介绍5.2. 数据容器运算符5.2.1. 成员运算符5.2.2. 身份运算符 5.3. 字符串str5.3.1. 字符串的定义5.3.2. 运算符的相关操作5.3.3. 索引和切片5.3.3.1. 索引5.3.3.2. 切片 5.3.4. 字符串遍历5.3.5. 字符串的相关操作5.3.5.1. 获取的…

git安装以及git小乌龟使用

一、下载git 打开git官网地址:https://git-scm.com/进行下载 下载完安装,一直next就好,如果愿意就可以改下安装路径,改在d盘。 具体可以参考:git安装教程 二、安装完下载小乌龟以及语言包 下载地址:小乌龟…

【OpenMMLab AI实战营二期笔记】第六天 目标检测和MMDetection

1.什么是目标检测? 目标检测 vs 图像分类 目标检测的应用 (1)人脸识别 (2)智慧城市 (3)自动驾驶 (4)下游视觉任务:场景文字识别、人体姿态估计 目标检测技术…

微服务 springcloud 08.zuul框架,API网关,整合ribbon和hystrix框架

01.zuul是作为springcloud中的一个网关框架来使用的。 zuul API 网关,为微服务应用提供统一的对外访问接口。 zuul 还提供过滤器,对所有微服务提供统一的请求校验。 在项目中的位置: 02.新建 sp11-zuul 项目 03.pom.xml 需要添加 sp01-com…

【雕爷学编程】Arduino动手做(111)---震动提醒模块

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&am…

纺织工厂运营神技,不会你就OUT了!

在纺织工业中,保持适宜的生产环境是至关重要的。温湿度、能耗、设备运行状态以及空气质量等因素对纺织品的质量和生产效率都有着重要影响。 为了实现对生产环境的全面监控和管理,纺织企业越来越多地采用动环监控系统。 客户案例 湖州市某纺织工厂监控项目…

USART2实现Motbus485通信

本文用的单片机是原子的战舰V4 1. 先来驱动一下usart2 USART驱动配置一般步骤: STEP1:使能相关时钟,这块板子usart2用到了A2、A3分别为TX脚、RX脚,D7的作用是发送接收模式控制。下面开启GPIO与USART2时钟: RCC_APB1PeriphClockCm…

SpringBoot中打印 sql 语句

系列文章目录 文章目录 系列文章目录前言一、在配置文件中 application.yml 配置即可二、#Log4g打印SqL语句三、配置Logback总结 前言 在SpringBoot中,我们可以使用日志框架来打印SQL语句,常用的日志框架有Logback和Log4j2。下面以Logback为例&#xff…

35:考虑virtual函数以外的其他选择

假设你正在写一个视频游戏软件,你打算为游戏内的人物设计一个继承体系,剧中人物被伤害或因其他因素而降低健康状态的情况并不罕见。你因此决定提供一个成员函数healthValue,它会返回一个整数,表示人物的健康程度。 由于不同的人物…

Linux x86_64平台同时编译x86_64和arm64两个架构的Qt应用程序出现XRes库无法找到

一 背景 在ubuntu x86_64平台上需要同时编译x86_64和arm64两个架构的Qt应用程序。在实践过程中,发现XRes库只能安装在其中一个平台。 二 根因 安装amd64版本的XRes库会删除arm64版本的库,反之亦然。 在安装amd64版本时,会删除arm64版本&a…

内部员工有没有在线帮助文档可以使用呢

当今企业中,内部员工的工作内容变得越来越复杂,需要不断学习新的知识和技能。在这种情况下,企业需要给员工提供一种便捷的在线帮助文档,使员工能够更加高效地完成工作任务。本文将介绍企业内部员工在线帮助文档的重要性以及如何建…

区块链如何助力价值互联网?这些专家有话说

6月13日,由开放原子开源基金会主办,XuperCore开源项目承办的2023开放原子全球开源峰会区块链分论坛在北京举办。来自区块链领域内的专家、行业代表汇聚一堂,分别以主题演讲、圆桌论坛等形式,阐述了全球区块链行业的新理念、新发展…

Opencv仿射函数getAffineTransform底层实现原理

推导 三角形ABC仿射成为三角形DEF的变换矩阵M 猜测矩阵M [ [a1,b1,c1], [a2,b2,c2] ] 仿射变换的数学联系 对于A点和D点 AX*a1AY*b1c1DX AX*a2AY*b2c1DY 对于B点和E点 BX*a1BY*b1c1EX BX*a2BY*b2c2EY 对于C点和F点 CX*a1CY*b1c1FX CX*a2CY*b2c2FY 求解 对以上数…

seqkit 两种拆分方法的比较

seqkit拆分fastq,fasta等文件有两种方式:split和split2, 二者的逻辑并不一样。 split 是将原文件拆分,写满第一个文件,再写第二个文件 split2是将原文件的内容,挨个写到各个拆分文件里面去? 比…

拓尔微技术干货 | get 5个知识点,了解细分驱动技术

本期我们对步进电机驱动原理、五线的步进电机和四线的步进电机、2-2相励磁和1-2相励磁、步进电机驱动的优化方案、拓尔微TMI8150B细分驱动技术的原理进行详细的介绍,共分为5个知识点,全是技术干货,赶紧get下来~ ✔get 1:步进电机…

datax安装部署使用 windows

Datax在win10中的安装_windows安装datax_JMzz的博客-CSDN博客 DataX/userGuid.md at master alibaba/DataX GitHub 环境准备: 1.JDK(1.8以上,推荐1.8) 2.①Python(推荐Python2.7.X) ②Python(Python3.X.X的可以下载下面的安装包替换) python3.0需…

Docker安装——CentOS7.6(详细版)

ps:docker官网 在 CentOS 上安装 Docker 引擎 |官方文档 () 一、确定版本(必须是7以上版本) cat /etc/redhat-release 二、卸载旧版本(或者之前装过,没有安装过就不用管了) (root用…

OpenCV 项目开发实战--实现填充图像中的孔( Python / C++ ) 代码实现

文末附分别基于C++和python实现的相关测试代码下载链接 图 1. 左:原始的图像。中心:阈值和倒置。右:孔被填充。 在本教程中,我们将学习如何填充二值图像中的孔洞。考虑图 1 中左侧的图像。假设我们想要找到一个将硬币与背景分开的二进制掩码,如右图所示。在本教程中,包含…

2.0C++继承

C继承概述 C 中的继承是指一个类可以从另一个类中继承属性和方法,这个被继承的类称为基类或父类,继承它的类称为派生类或子类。 C三种继承 1、公有继承 public 在公有继承中,基类的公有成员和保护成员都可以被派生类访问,而基…

【ROS】ROS2导航Nav2:简介、安装、测试效果、错误处理

1、简介 在ROS2中自动导航使用Nav2来实现。 Nav2 使用几个独立的模块化服务,通过 ROS 2接口(例如动作服务器或服务)与行为树 (BT) 通信。 Nav2 输入包括:TF转换、一个地图源、一个行为树 (BT) XML 文件和相关的传感器数据源; Nav…