Redis数据结构—跳跃表 skiplist 实现源码分析

Redis 是一个开源的内存数据结构存储系统,它可以用作数据库、缓存和消息中间件。Redis 的数据结构非常丰富,其中跳跃表(skiplist)是一种重要的数据结构,它被用来实现有序集合(sorted sets)。

跳跃表是一种概率型数据结构,它通过多层链表来实现快速的查找操作。跳跃表的结构类似于多层索引,每一层都是一个有序链表,但每一层的链表节点数量逐渐减少,最顶层的链表节点最少,最底层的链表节点最多。这样设计的好处是,可以在对数时间内完成查找操作,同时插入和删除操作也非常高效。

跳跃表的主要特点包括:

有序性:跳跃表中的元素是有序的,可以快速地进行范围查询。
概率性:跳跃表的高度是随机决定的,这使得它在平均情况下具有对数时间复杂度。
动态性:跳跃表可以在运行时动态地添加和删除元素,而不需要重新构建整个结构。
空间效率:相比于平衡树,跳跃表的空间效率更高,因为它不需要存储指向父节点的指针。

在 Redis 中,跳跃表被用于实现有序集合,它允许用户添加、删除、更新和查询元素,并且可以按照分数对元素进行排序。跳跃表的实现细节在 Redis 源码中可以找到,它是 Redis 高效性的关键因素之一。

以下是根据 Redis 源码对其实现原理的详细分析:

数据结构定义:
Redis 中的跳跃表由 zskiplistNode 和 zskiplist 两个结构体定义。zskiplistNode 表示跳跃表的节点,包含成员对象 obj、分值 score、后退指针 backward 以及层 level 信息;zskiplist 表示跳跃表本身,包含头尾节点指针、长度和层高信息。

节点层级:
跳跃表的每个节点可以有多个层,称为索引层,每个索引层包含一个前向指针 forward 和跨度 span。层高是随机生成的,遵循幂次定律,最大层高为 32。

创建跳跃表:
使用 zslCreate 函数创建一个新的跳跃表,初始化层高为 1,长度为 0,并创建头节点,头节点的层高为 32,其余节点的层高根据需要动态生成。

插入节点:
插入操作首先确定新节点的层高,然后从高层向低层搜索插入位置,并更新 update 数组,该数组记录所有需要调整的前置节点。接着,创建新节点,并根据 update 数组和 rank 数组更新跨度和前向指针。

查找操作:
查找操作从高层开始,沿着链表前进;遇到大于目标值的节点时下降到下一层,继续查找。经过的所有节点的跨度之和即为目标节点的排位(rank)。

删除节点:
删除操作根据分值和对象找到待删除节点,并更新相关节点的前向指针和跨度。如果节点在多层中存在,需要逐层删除。

性能分析:
跳跃表支持平均 O(logN)、最坏 O(N) 复杂度的节点查找,且实现比平衡树简单。在有序集合中,跳跃表可以处理元素数量较多或元素成员较长的情况。

Redis 应用场景:
Redis 使用跳跃表实现有序集合键,特别是当集合中的元素数量较多或元素的成员是较长的字符串时。跳跃表也用于 Redis 集群节点中的内部数据结构。

跳跃表的优点:
跳跃表的优点包括支持快速的查找操作,以及在实现上相对简单。它通过维护多个层级的链表来提高查找效率,且可以顺序性地批量处理节点。

跳跃表的实现细节:
跳跃表的实现细节包括节点的创建、插入、删除、搜索等操作,以及维护跳跃表的最大层高和节点数量等信息。具体实现可以参考 Redis 源码中的 t_zset.c 文件。

Redis 的跳跃表实现是对其有序集合性能和功能的重要支撑,通过上述分析,我们可以更深入地理解这一数据结构的内部机制。

结合 Redis 源码中的跳跃表实现,我们可以深入理解其工作原理。以下是根据 Redis 源码中的跳跃表实现代码进行的分析:

跳跃表节点定义 (zskiplistNode)

typedef struct zskiplistNode {robj *obj; // 指向成员对象的指针double score; // 分数值struct zskiplistNode *backward; // 后退指针,用于从后往前遍历struct zskiplistLevel {struct zskiplistNode *forward; // 前进指针unsigned int span; // 跨度,表示该层跨越的元素数量} level[]; // 索引层,包含多个索引
} zskiplistNode;

跳跃表定义 (zskiplist)

typedef struct zskiplist {struct zskiplistNode *header, *tail; // 头尾节点指针unsigned long length; // 跳跃表的长度,即元素数量int level; // 跳跃表的最大层数
} zskiplist;

跳跃表的创建 (zslCreate)

zskiplist *zslCreate(void) {int j;zskiplist *zsl = zmalloc(sizeof(*zsl));zsl->level = 1;zsl->length = 0;zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL, 0, NULL);// 初始化头节点的各个层的跨度和前向指针for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {zsl->header->level[j].forward = NULL;zsl->header->level[j].span = 0;}zsl->header->backward = NULL;zsl->tail = NULL;return zsl;
}

跳跃表的插入 (zslInsert)


zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj) {// ...// 1. 初始化更新数组和 rank 数组// 2. 从高层向底层搜索,找到每个层级的插入位置// 3. 确定新节点的层数// 4. 创建新节点,并更新前向指针和跨度// 5. 更新跳跃表的最大层数和长度// ...
}

跳跃表的搜索 (zslGetRank)


unsigned long zslGetRank(zskiplist *zsl, double score, robj *o, int reverse) {// ...// 1. 从高层向底层搜索目标元素// 2. 累加跨度以计算元素的排名// ...
}

跳跃表的删除 (zslDelete)


zskiplistNode *zslDelete(zskiplist *zsl, double score, robj *obj) {// ...// 1. 搜索目标元素并记录需要更新的节点// 2. 逐层删除节点// 3. 更新跨度和前向指针// 4. 如果删除了头节点,更新头节点// ...
}

跳跃表的高度随机化

Redis 中节点的层高是随机决定的,通常使用固定概率(如 1/2)来确定。但在 Redis 实现中,节点的层高是根据幂次定律随机生成的,介于 1 和 32 之间。

总结

Redis 的跳跃表实现涉及多个关键操作:创建、插入、搜索和删除。每个操作都需要对节点的层级和跨度进行精确管理,以保证跳跃表的有序性和高效的查找性能。跳跃表的高度随机化和层级结构的设计使得 Redis 能够在对数时间内完成查找操作,同时保持了较高的空间效率和动态性。通过源码分析,我们可以更深入地理解 Redis 中跳跃表的内部机制和实现细节。

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

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

相关文章

三维点云配准 -- ICP 算法原理及推导

三维点云配准 -- ICP 算法原理及推导 - 知乎 (zhihu.com) 三维点云配准 -- ICP 算法 | Yilins Blog Alex Segal - Research - Generalized-ICP (ox.ac.uk)

一个项目学习Vue3---if、else、show、for的使用

观察下面代码学习这部分内容 <!--条件和列表渲染--> <template><button click"stateChang">状态切换{{ flag }}</button><span v-if"flag">显示这个</span><span v-else-if"!flag">显示那个Else<…

算法力扣刷题记录 三十八【二叉树的层次遍历应用一及二叉树构建】

前言 二叉树层序遍历应用题目。 记录三十八 【二叉树的层次遍历应用一】 继续。 一、【107.二叉树的层次遍历 II】 题目 给你二叉树的根节点 root &#xff0c;返回其节点值 自底向上的层序遍历 。 &#xff08;即按从叶子节点所在层到根节点所在的层&#xff0c;逐层从左向…

WTM的项目中EFCore如何适配人大金仓数据库

一、WTM是什么 WalkingTec.Mvvm框架&#xff08;简称WTM&#xff09;最早开发与2013年&#xff0c;基于Asp.net MVC3 和 最早的Entity Framework, 当初主要是为了解决公司内部开发效率低&#xff0c;代码风格不统一的问题。2017年9月&#xff0c;将代码移植到了.Net Core上&…

03_Shell变量

【Shell】03_Shell变量 一、环境变量 Linux系统配置文件&#xff08;全局配置文件和用户个人配置文件&#xff09;中定义的变量&#xff0c;提供给所有Shell程序使用 1.1、全局环境变量 1.1.1、配置文件位置 /etc/environment /etc/bashrc&#xff08;或者/etc/bash.bashrc…

《梦醒蝶飞:释放Excel函数与公式的力量》10.1.1函数简介

10.1.1函数简介 BIN2DEC函数是Excel中用于将二进制数转换为十进制数的函数。它在处理二进制数时非常有用&#xff0c;尤其是在电子工程、计算机科学等领域。 10.1.2函数语法&#xff1a; BIN2DEC(number) number&#xff1a;这是要转换的二进制数&#xff0c;必须是以字符串…

通过软件资产管理系统实现NX软件许可证的精准管理!

引言 在现代企业中&#xff0c;NX软件许可证管理是IT运维工作的重要组成部分。然而&#xff0c;用户部门反映NX许可证不够用且使用紧张&#xff0c;但缺乏可靠的数据支持&#xff0c;导致许可证的采购和管理面临挑战。本文将介绍如何利用smartlic软件资产管理系统&#xff0c;…

HNU小学期BSP软件编程基础十道测试题

http://t.csdnimg.cn/Yv0R1 文章参考了这位大佬的代码&#xff0c;在他的基础上进行了纠错、完善等处理。 配置 编程前的准备工作按大佬的流程即可&#xff0c;稍有不同的是学习通课程网站的资料里没有头文件的整个压缩包了&#xff0c;但我们可以下载某个BSP版的工程文件&am…

C语言 找出一个二维数组中的鞍点

找出一个二维数组中的鞍点,即该位置上的元素在该行上最大、在该列上最小。也可能没有鞍点。 #include <stdio.h>int main() {int matrix[4][4] {{10, 17, 13, 28},{21, 14, 16, 40},{30, 42, 23, 39},{24, 11, 19, 17}};int n 4, m 4;int found 0;for (int i 0; i …

磁力搜索引擎是什么?为什么有些资源喜欢用磁力链接?

磁力链接是什么东西&#xff1f;在日常生活中&#xff0c;我们接触的比较多的下载链接是直链。 所谓的直链简单来说就是直接指向服务器文件资源的链接&#xff0c;如B站app的下载链接&#xff0c;这种链接有统一的服务器提供保障&#xff0c;通常比较稳定&#xff0c;可以追溯源…

python调用qt编写的dll

报错&#xff1a;FileNotFoundError: Could not find module F:\pythonProject\MINGW\sgp4Lib.dll (or one of its dependencies). Try using the full path with constructor syntax. 只有两种情况&#xff1a; 1.路径不对 2.库的依赖不全 1、如果是使用了qt库的&#xff0…

transformer的了解

1.transformer的优化策略 1&#xff09;GQA&#xff0c;减少推理过程中的KV缓存大小&#xff0c;增加上下文长度&#xff08;KV 缓存&#xff08;即 Key-Value 缓存&#xff09;用于加速 Transformer 模型在推理过程中处理长序列时的计算。要减少 KV 缓存的大小&#xff09; 2&…

JAVA Tesseract OCR引擎

Tess4j是一个基于Tesseract OCR引擎的Java库, Tesseract库最初由惠普实验室于1985年开发&#xff0c;后来被Google收购并于2006年开源。识别效果不好&#xff0c;速度还慢&#xff0c;但是好早好早了。 一、POM依赖 <!--OCR识别https://digi.bib.uni-mannheim.de/tesserac…

一文洞悉巴基斯坦电子游戏出海引流获客广告风口不容忽视

一文洞悉巴基斯坦电子游戏出海引流获客广告风口不容忽视 随着全球数字经济的蓬勃发展&#xff0c;电子游戏行业也迎来了前所未有的机遇。巴基斯坦&#xff0c;这个拥有庞大人口基数和日益增长的消费能力的国家&#xff0c;其电子游戏市场潜力巨大。本文旨在探讨巴基斯坦电子游戏…

springboot驾校管理系统-计算机毕业设计源码49777

驾校管理系统 摘 要 驾校管理系统是一个基于Spring Boot框架开发的系统&#xff0c;旨在帮助驾校提高管理效率和服务水平。该系统主要实现了用户管理、年月类型管理、区域信息管理、驾校信息管理、车辆信息管理、报名信息管理、缴费信息管理、财务信息管理、教练分配管理、更换…

获取和设置Spring Cookie

一.获取浏览器中的cookie public void testGetCookie(HttpServletRequest request){//request获取的Cookie是个数组Cookie[] cookies request.getCookies();if (cookies ! null&&cookies.length>0) {for (Cookie cookie : cookies) {//获取Cookie名称String cooki…

探索未知,悦享惊喜 —— 您的专属盲盒APP开发之旅

在这个充满无限可能的数字时代&#xff0c;每一份期待都值得被精心打造。我们诚邀您一同踏入盲盒APP开发的奇妙世界&#xff0c;共同开启一场融合趣味、惊喜与社交的全新体验。 【概念启航&#xff1a;盲盒文化的数字化演绎】 盲盒&#xff0c;这一源自传统玩具的趣味玩法&am…

java Object 转 Integer

在 Java 中&#xff0c;可以通过多种方法将一个 Object 转换为 Integer。这里有几种常见的方法&#xff1a; 使用类型转换和自动装箱&#xff08;如果 Object 实际上是一个 Integer 类型&#xff09;&#xff1a; Object obj 42; // 假设这是一个 Integer 对象 if (obj instan…

Java面试题系列 - 第6天

题目&#xff1a;深入理解Java内存模型&#xff08;JMM&#xff09;及线程可见性 背景说明&#xff1a;Java内存模型&#xff08;Java Memory Model&#xff0c;简称JMM&#xff09;是Java虚拟机规范的一部分&#xff0c;用于描述Java程序中各种变量&#xff08;线程共享变量&…

含空格字符串处理方法总结

读取按单个字符判断的字符串 chcin.get() 读取含空格的字符串方法 getline(cin,s); 想要对回车符号单独处理 getchar() //吸收回车符 真题练习&#xff0c;用字符串流的方法处理空格情况。 通用方法&#xff1a;字符串流 istringstream ss(字符串)(ss >> )分割。 151…