Redis中的有序集合及其底层跳表

news2024/9/24 1:21:39

前言

本文着重介绍Redis中的有序集合的底层实现中的跳表

有序集合 Sorted Set

Redis中的Sorted Set 是一个有序的无重复值的集合,他底层是使用压缩列表和跳表实现的,和Java中的HashMap底层数据结构(1.8)链表+红黑树异曲同工之妙

什么是跳表

跳跃表(Skip List)是一种有序的数据结构,它由多层有序链表组成。每一层链表中的节点是有序排列的,而每一层链表中的节点指针可以跨越若干个节点,这样就提高了查询效率。

  1. 跳跃表最底层的链表包含了所有的元素,而每一层链表都是下一层链表的子集。最顶层链表只有两个节点,即头节点和尾节点。每一层链表中的节点包含了一个成员(Member)和一个指向同样成员的下一层链表节点的指针。

  2. 通过使用跳跃表,可以在时间复杂度O(logN)的情况下执行插入、删除和查找操作。这相比于传统链表的时间复杂度O(N)来说更加高效。同时,跳跃表还相对于平衡二叉树来说更加简单,容易实现。

其实就是经典的空间换时间,利用“跳跃节点”在层级间跳跃,每层都保留数据,从下往上,数据越来越少,图示如下:
在这里插入图片描述

跳表的查询流程

跳表的查询流程其实很简单,举个例子假如我们要查找value == 6,正常链表需要遍历4次才能找到,而跳表3次就可以了。
其过程就是,1->1->2->6,1->1这个直接过去的,不需要额外判断,也就是1->2->6这个过程,图示如下:
在这里插入图片描述
其原理就和二分查找一样,首先顶层的1节点判断小于就往下右走到第二层的2节点,然后往右走,就找到6了

同样的,如果查找4节点,1->1->2->2->4,在一层中如果下一个节点的值比目标值还大的值就直接往下走,因为下层的数据的范围一定在[Node.value,Node.next.value]之间,当前例子中就是4一定在下一层的[2,6]节点中。这样就可以做到快速访问了,在数据量大的情况下,他的时间复杂度就是O(logN)。

跳表的插入

在Redis中,跳表的每一层链表都有一个编号,从下往上是0~31,当我们要进行插入操作的时候,Redis 会生成一个随机数,这个随机数的范围是[1,32],这个随机数越大,生成的概率就越小,意思就是生成1的概率为50%,2的概率为25%,逐层减半。源码如下:

static unsigned int ziplistLength(unsigned char *zl) {
    return ziplistLen((unsigned char*)zl);
}

// 生成一个介于1和2^32之间的随机数
static unsigned int zrandom(void) {
    // 以秒为种子生成随机数
    srand(time(0));
    return rand();
}

typedef struct zskiplistNode {
    // 成员对象
    sds ele;
    // 分值
    double score;
    // 后退指针
    struct zskiplistNode *backward;
    // 层
    struct zskiplistLevel {
        // 前进指针
        struct zskiplistNode *forward;
        // 跨度(跨过的节点数量)
        unsigned int span;
    } level[];
} zskiplistNode;

typedef struct zskiplist {
    // 头节点和尾节点
    struct zskiplistNode *header, *tail;
    // 节点数量
    unsigned long length;
    // 层数
    int level;
} zskiplist;

// 创建并返回一个新节点
static zskiplistNode *zslCreateNode(int level, double score, sds ele) {
    // 分配节点空间
    zskiplistNode *zn = zmalloc(sizeof(*zn) + level * sizeof(struct zskiplistLevel));
    // 设置节点成员
    zn->score = score;
    zn->ele = ele;
    return zn;
}

// 创建并返回一个新的跳跃表
zskiplist *zslCreate(void) {
    int j;
    // 分配空间
    zskiplist *zsl = zmalloc(sizeof(*zsl));
    // 初始化头节点
    zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL, 0, NULL);
    // 设置尾节点
    zsl->tail = NULL;
    // 初始化长度和层数
    zsl->length = 0;
    zsl->level = 1;
    // 初始化头节点的 forward 和 span
    for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
        zsl->header->level[j].forward = NULL;
        zsl->header->level[j].span = 0;
    }
    // 初始化尾节点
    zsl->header->backward = NULL;
    return zsl;
}

// 随机生成节点层数
int zslRandomLevel(void) {
    int level = 1;
    // 每隔2个节点,层数+1(以1/4的概率)
    while ((zrandom() & 0xFFFF) < (ZSKIPLIST_P * 0xFFFF)) {
        level += 1;
    }
    return (level < ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

这个随机数的意义就是数据在插多少层,举个例子,假如我随机到5,那么就意味着我的数据要从的0~4层进插入,这样才能保证我新来的数据不会影响到我跳表下层兼容上层的特性,也能保证数据访问的快速性(因为不一定要到底层查数据有可能我上一层就查到了),图示如下(random== 2,value== 5):
在这里插入图片描述

压缩列表升级为跳表

在Java的HashMap中,是要到table.length >= 64 && list.length >= 8 时才会出现一个从链表升级到红黑树的过程,在我们的Redis中也是如此,只要不满足其中一个,就会升级 (||运算)

1. 有序集合中的元素个数小于128个
2. 有序集合保存的元素成员长度都必须小于64字节

当以上任意一个不满足时,就会从压缩列表升级为跳表

以上是本节的全部内容

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

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

相关文章

派森 #P122. 峰值查找

描述 给定一个长度为n的列表nums&#xff0c;请你找到峰值并返回其索引。数组可能包含多个峰值&#xff0c;在这种情况下&#xff0c;返回任何一个所在位置即可。 &#xff08;1&#xff09;峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于&#xff1b; &…

ARM体系结构学习笔记:过程调用标准AAPC、 ARM32调用约定、ARM64调用约定

参数传递的本质: 将上层函数变量复制一份, 传给下层函数. 过程调用标准AAPC(Arm Architecture Procedure Call) 有了标准, 才能够进行C调用汇编或者汇编调用C ARM32调用约定 参数是不同位数传参情况, 额外的参数被caller进行入栈, callee进行出栈 寄存器传参 寄存器返回 汇编…

交叉编译相关知识

1、目标板与主机之间的连接&#xff1a; 目标板和主机之间通常可以使用串口、以太网接口、USB接口以及JTAG接口等连接方式。 (1)、串行通信&#xff1a; 串行通信接口常用的有9针串口&#xff08; DB9 &#xff09;和25针串口&#xff08;DB25&#xff09;&#xff0c;通信距…

IDEA创建Mybatis格式XML文件

设置位置&#xff1a;File | Settings | Editor | File and Code Templates 选择Files&#xff0c;点击号 Name中输入xml模板名&#xff08;名称自行决定&#xff09;&#xff0c;后缀名extension输入xml&#xff08;固定&#xff09; 内容处输入Mybatis的xml文件模板内容&…

数据结构 - 线性表的定义和基本操作

一、定义 线性表是具有相同特性的数据元素的一个有限序列。 线性表&#xff1a; 由n(n≥0)个数据元素&#xff08;结点&#xff09;组成的有限序列。线性表中数据元素是一对一的关系&#xff0c;每个结点最多有一个直接前驱&#xff0c;和一个直接后继 二、线性表的基本操作 …

【AI绘画--七夕篇】:七夕特别教程,使用SDXL绘制你的心上人(Stable Diffusion)(封神榜—妲己)

目录 前言0、介绍0-0、结果展示0-1、Stable Diffusion0-2、sdxl介绍 一、云端部署Stable Diffusion1-1、云端平台的优势 二、平台介绍三、注册账号并且开始炼制3-1、购买算力并创建工作空间3-2、启动工作空间3-3、应用市场一键安装3-4、使用Stable-Diffusion作图 四、有女朋友的…

cuda gdb调试

如果cudaDeviceEnablePeerAccess函数不支持或不起作用&#xff0c;您仍然可以尝试其他方法来实现GPU之间的数据交换和通信。以下是一些替代方法&#xff1a; 通过主机内存进行数据传输&#xff1a; 如果GPU之间的数据交换不是非常频繁&#xff0c;您可以将数据从一个GPU复制到…

【c语言】五子棋(EasyX图形库+背景音乐)

大家好&#xff0c;有没有觉得写了好多c语言代码&#xff0c;面对的都是黑框框控制台&#xff0c;当我们学习了基础的c语言知识&#xff0c;和EasyX图形库后&#xff0c;终于可以和黑框框saygoodbye,今天要分享给大家的是小游戏五子棋&#xff0c;跟着小张一起学习吧 EasyX图形…

(四)Doceke安装MySQL镜像+Docker启动MySQL容器

Doceke安装MySQL镜像/Docker启动MySQL容器 一、doceke安装MySQL镜像 切换到root用户&#xff0c;su root 。 1、启动Docker 启动&#xff1a;sudo systemctl start docker 停止&#xff1a;systemctl stop docker 重启&#xff1a;systemctl restart docker 查看docker运行…

视频汇聚平台EasyCVR安防视频监控在地下停车场中的具体应用方案

一、背景 随着我国城市化进程的加快&#xff0c;汽车已成为人们生活中不可缺少的交通工具&#xff0c;但在许多城市中&#xff0c;买车容易&#xff0c;停车难的问题愈发突出。特别是在人群密集的商场、写字楼和地下停车场&#xff0c;车流量大、车况复杂。传统的人工判断方式耗…

go、java、.net、C#、nodejs、vue、react、python程序问题进群咨询

1、面试辅导 2、程序辅导 3、一对一腾讯会议辅导 3、业务逻辑辅导 4、各种bug帮你解决。 5、培训小白 6、顺利拿到offer

【网络基础实战之路】基于三层架构实现一个企业内网搭建的实战详解

系列文章传送门&#xff1a; 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 【网络基础实战之路】基于…

Lombok生成的Getter和Setter的名称对于“eMail”或“xAxis”等属性存在大小写转换异常

问题 最新开发中&#xff0c;遇到一个字段映射问题。我们先看问题案例&#xff1a; 明明代码中第二个字母是大写&#xff0c;结果测试接口时发现变成了小写字母。 分析 通过网上查询发现&#xff0c;这属于Lombok的bug。而且早在2015年就有人在GitHub上提出了issues。 Names o…

基于SpringBoot房产销售系统【附ppt|开题|万字文档(LW)和搭建文档】

主要功能 前台界面&#xff1a; ①首页、房源信息推荐、房源信息展示、查看更多等 ②房源信息、房源名称、房源户型、销售姓名等 ③购房、预约、点我收藏、评论等 ④个人中心、我的收藏、支付等 后台登录&#xff1a; ①首页、个人中心&#xff1a;修改密码、用户信息管理等 ②…

三角函数与圆,角度和弧度 (草稿,建设中)

目录 1 三角函数与圆&#xff0c;角度和弧度 1.1 三角形 1.2 圆形 2 角度 3 弧度 rad 4 角度&#xff0c;弧度的换算 2 三角函数 1 三角函数与圆&#xff0c;角度和弧度 1.1 三角形 角度弧长sin()cos()tan() 1.2 圆形 半径&#xff0c;周长&#xff0c;弧长半径面积 …

Linux面试笔试题(2)

27、按下( A ) 键能终止当前运行的命令 A. Ctrl-C B. Ctrl-F C. Ctrl-B D. Ctrl-D 28、下面哪个命令用来启动X Window ( C ) A. runx B. Startx C. startX D. xwin 29、用 “rm -i”,系统会提示什么来让你确认( B ) A.命令行的每个选项 B.是否真的删除 C.是否有写的权限 D…

计算机网络第2章(物理层)

计算机网络第2章&#xff08;物理层&#xff09; 2.1 物理层的基本概念2.2 物理层下面的传输媒体2.2.1 导引型传输媒体2.2.2 非导引型传输媒体 2.3 传输方式2.3.1 串行传输和并行传输2.3.2 同步传输和异步传输2.3.3 单向通信&#xff08;单工&#xff09;、双向交替通信&#x…

【Leetcode】105.从前序与中序遍历序列构造二叉树

一、题目 1、题目描述 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。 示例1: 输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]示例…

口腔牙科门诊挂号系统 微信小程序的设计与实现_1171u-

随着信息时代的来临&#xff0c;过去的“口腔助手”管理方式缺点逐渐暴露&#xff0c;现在对过去的“口腔助手”管理方式的缺点进行分析&#xff0c;采取计算机方式构建“口腔助手”小程序。本文通过阅读相关文献&#xff0c;研究国内外相关技术&#xff0c;提出了一种预约信息…

睿趣科技:抖音小店新人最适合卖什么产品

随着移动互联网的不断发展&#xff0c;短视频平台如今已经成为了人们日常生活中不可或缺的一部分。其中&#xff0c;抖音作为国内短视频平台的代表&#xff0c;不仅让用户可以欣赏到各种有趣、创意的短视频内容&#xff0c;同时也为创业者提供了一个广阔的创业机会——抖音小店…