「Redis数据结构」跳跃表(SkipList)

news2025/1/12 8:46:32

「Redis数据结构」跳跃表(SkipList)

文章目录

  • 「Redis数据结构」跳跃表(SkipList)
    • 一、概述
    • 二、结构
      • 跳跃表节点
      • 跳跃表
    • 三、特点

一、概述

跳表(SkipList,全称跳跃表)是用于有序元素序列快速搜索查找的一个数据结构,跳表是一个随机化的数据结构实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。

跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。它在性能上和红黑树,AVL树不相上下,但是跳表的原理非常简单,实现也比红黑树简单很多。


二、结构

Redis 的跳跃表由 redis.h/zskiplistNoderedis.h/zskiplist 两个结构体定义。

跳跃表节点

redis.h/zskiplistNode结构用于保存跳跃表节点的相关信息。

/* 跳跃表节点 */
typedef struct zskiplistNode {  
    robj *obj;     // 成员对象
    double score;    // 分值 
    struct zskiplistNode *backward;    // 后退指针
    // 层
    struct zskiplistLevel
    {
        struct zskiplistNode *forward;    // 前进指针
        unsigned int span;    // 跨度
    } level[];
};

  • 跳跃表节点的level数组可以包含多个元素,每个元素都包含一直指向其他节点的指针。
    程序可以通过这些层来加快访问其他节点的速度。
  • 前进指针
  • 跨度
    层的跨度用于记录2个节点之间的距离
    • 2个节点之间的
  • 后退指针
  • 分值和成员

跳跃表

/* 跳跃表 */
typedef struct zskiplist
{
    struct zskiplistNode *header;    // 头节点
    struct zskiplistNode *tail;      // 尾节点
    unsigned long length;    // 表中节点的数量
    int level;      // 表中层数最大的节点的层数
} zskiplist;
  • header
    指向跳跃表的表头节点
  • tail
    指向跳跃表的表尾节点
  • level
    记录米钱跳跃表层内,层数最大呃那个节点层数。
  • length
    记录跳跃表的长度

下面是一个普通的排序单向链表

image-20221209100622984

如果你想寻找这个链表中有没有节点8,那么你就要从节点1开始,依次向后遍历,直到遍历到一个数值等于8的节点,返回true这个答案。

那么如何能让这个遍历的次数减少呢?

我们可以考虑这原有链表上面建立一个索引层,索引层的节点是最底层链表节点的一部分,然后索引层的节点有一个指针指向下一层节点自己的本体节点。

image-20221209100647877

在查询的时候,我们可以从索引层去查询,先找到节点1,然后到节点4,然后到节点7,节点7之后没有节点了,那么就去下一层去寻找,下一层的节点7之后就是节点8,这次我们只遍历了4次就找到了答案。

那么上层的节点层的个数取多少合适呢?如果我们下层的节点个数是10W个,而上层只有三个索引节点的话,从节点7之后遍历,也要遍历9W多个,肯定是达不到我们预期的效率的。所以最好的策略就是,上层节点的个数是下层节点个数的一半,且尽量是随机均匀的,这样就可以节省一半的遍历次数,比如有10W个节点,我们就建立5W个索引节点,这样遍历次数就可以减少一半。

但是遍历5W次肯定也是不行的,我们知道O(n)和O(2n)这种在算法中是近似相等的,那么怎么办呢?一层不够我们就建立两层,两层不够就建立三层。直到最上层的节点个数是一两个,这样一层一层查找下去,我们就可以做到对数级别的时间复杂度,就可以媲美二分查找。

image-20221209100751762

为什么不选用红黑树

红黑树也拥有二叉搜索树的特性,查找节点的时候拥有二分查找的性能,而且不用多余的内存空间。但是红黑树对范围搜索的支持就比较单调了,使用跳表来做范围查询,只需要找到头节点,然后往后遍历就好了,但是红黑树呢?找到头节点之后,你依然不知道它之后节点在哪,你只知道在左子树上,剩下你啥都不知道,就要继续遍历去找。

Redis的作者也说明过为什么使用跳表,大概就三点

  • 虽然跳表消耗较多的内存,但是我们内部优化过跳表,可以接受。
  • 跳表的实现很简单,至少比红黑树简单的多。
  • 多范围查询的支持,跳表完胜红黑树。

三、特点

  • 跳表结合了链表和类似二分查找的思想;
  • 有很多层结构,由原始链表和一些通过“跳跃”生成的链表组成;
  • 每一层都是一个有序的链表;
  • 最底层(Level 1)的链表包含所有元素,越上层“跳跃”的越高,元素(索引)越少;
  • 查找时从顶层向下,不断缩小搜索范围;
  • 上层链表是下层链表的子序列;
  • 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。

参考

《Redis 设计与实现》

Redis跳表底层实现

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

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

相关文章

shell编程二

目录语法引号exprtestif...then...fiif...elseif...elseif嵌套case…esacforwhilebreak 和 continue函数语法 引号 " ":如果有字符串,字符串原样输出,如果有$变量则查看变量的值 :所有的字符无论是否有变量都原样输出 ˋˋ:在该引号包含的…

如何批量查询网站的搜狗收录情况?搜狗收录么查询

如何批量查询网站的搜狗收录情况?搜狗收录么查询 查询网站的搜狗收录的具体操作: 第一步、打开网站综合查询工具 第二步、添加需要查询的网站域名 第三步、勾选要查询的功能(勾选搜狗是否收录和搜狗总收录) 第…

redis 主从复制(读写分离)集群搭建(含错误处理)

目录 1.概述 2.搭建 2.1.安装配置 2.2.认主 2.3.错误处理 3.原理 1.概述 当面临大流量时,redis可以采取集群的方式进行扩容,将压力分散到集群中的多个结点上去防止redis被打挂。redis的扩容方式有两种: 垂直扩容,即读写分离…

【移动端测试】了解Android的配置和使用过程

Android 是基于JAVA语言来进行开发编写的,但是对于Android体系中最底层是Linux层,现在说一下android 项目的结构目录: 整体结构和一个普通的java项目很类似 每一个项目都有一个主Activity 相当于java类中的main 方法是程序的入口 比如 该项目中的ListVi…

centos7搭建nginx主从以及集群

一、nginx升级之路 之前因为业务量并不是很大,所以公司nginx采用的是单机。因为nginx单机性能也很好,所以也没有发生过什么问题。不过后来还是慢慢进行了几次调整。最终换成了多IP地址解析和nginx主从。下面就介绍一下怎么一步步升级的。 1.最初版本&a…

天翼物联携手6家单位发起移动物联网高质量发展共同倡议

近日,由工信部指导,中国信息通信研究院(以下简称“中国信通院”)、中国通信学会、无锡市人民政府、人民邮电报社、江苏省工业和信息化厅、江苏省通信管理局共同主办,无锡物联网创新促进中心、天翼物联科技有限公司等单…

uniapp中tabBar菜单栏的实现以及页面常用的生命周期(菜单栏颜色切换)

前言 本篇文章带大家使用uniapp通过小案例实现tab菜单栏的切换,并对页面中常用的生命周期进行介绍。 实现菜单栏的切换 配置page页面 我们这里要实现三个页面的切换,所以要先在page.json文件中配置三个页面的路径 "pages": [ //pages数组…

HTML -- 一文学会HTML及常用标签

文章目录1. HTML简介1.1 网页1.1.1 什么是网页1.1.2 什么是HTML1.1.3 网页的形成1.2 常用浏览器1.2.1 常见的浏览器1.2.2 浏览器内核1.3 Web标准1.3.1 为什么需要Web标准1.3.2 Web标准的构成2. HTML基础2.1 HTML语法规范2.1.1 基本语法规范2.1.2 标签关系2.2 HTML基本结构标签2…

我做软件测试工作的两大乐趣

大家好,我是小谭。 曾几何时,我们都有一个梦想,梦想着做自己喜欢的工作。但现实往往事与愿违,我们被家庭、身份、社会捆绑,做着自己不喜欢的工作,即便做着自己喜欢的工作,也容易在日常的琐碎中…

SAAS系统和ERP区别?

saas系统和erp区别? saas是云计算应用的一种形式,而传统erp系统并不具备此特征;saas系统的数据存储也是在云端上,只要使用的软件即可用于业务管理的属于ERP的类别。 saas行业和传统软件区别很大吗? 很大,一个是新兴产…

C#捐款信息管理系统

捐款信息管理系统 技术 C#sqlserver 主要功能 登录、注册功能,两种角色登录判断,一种为管理员,一种为用户管理员发起项目,即发布项目,同时拥有对项目的增加、删除、修改、查询用户对管理员发起的项目可以进行申请操…

魏副业而战:做闲鱼副业项目的3个阶段

我是魏哥,与其在家躺平,不如魏副业而战! 小伙在社群提问:有没整套的模板案例? 他找了一上午的同行,没有找到“完整”的案例,他很苦恼,所以想请老师指导一下。 其实呢,…

wait_queue如何使用

Linux内核的 等待队列(Wait Queue)是重要的数据结构,与进程调度机制紧密相关联,可以用来同步对系统资源的访问、异步事件通知、跨进程通信等。如下图所示, 在Linux中,等待队列以循环链表为基础结构&#xf…

基于web的实验教学管理系统java ssm教学视频平台源码和论文

研究背景 近几年来,随着地方高等院校办学规模的不断扩大,为了适用社会发展需要,地方高校将应用 型人才培养作为学校的人才培养目标。为了适应学校应用型人才培养目标,各专业尤其是理工科专 业人才培养方案中加强了实践教学环节&a…

1559_AURIX_TC275_RCU系统中的Boot支持、Pad配置以及NMI trap处理

全部学习汇总: GreyZhang/g_TC275: happy hacking for TC275! (github.com) 这一次看的10页文档虽然文字内容不多,但是涉及到的面还是很多的。而且,看完之后的确是有一种答疑解惑的畅快感。 1. ESRx作为GPIO用的时候,也拥有GPIO设…

高等数学(第七版)同济大学 习题11-1 个人解答

高等数学(第七版)同济大学 习题11-1 函数作图软件:Mathematica 1.设在xOy面内有一分布着质量的曲线弧L,在点(x,y)处它的线密度为μ(x,y),用对弧长的曲线积分分别表达:\begin{aligned}&1. \ 设在xOy面内…

蓝桥杯嵌入式MCP4017

文章目录前言一、查看MCP4017芯片手册二、MCP4017在开发板上的电路图三、工程配置四、MCP4017读写函数编写总结前言 MCP4017是一个可编程电阻,通过写入数值可以调节电阻值的大小。 一、查看MCP4017芯片手册 在这里我们只需要关注MCP4017即可。下面的几个重要点我…

广播、组播 socket编程

目录 1、单播 / 广播 / 组播 的概念 (1) 单播 (2) 广播 (3) 多播(组播) 2、广播 socket编程(只能是UDP通信) 3、多播 socket编程(只能是UDP通信) 1、单播 / 广播 / 组播 的概念 (1) 单播 之前在进行…

m基于FPGA的MSK调制解调系统verilog开发,并带FPGA误码检测模块和matlab仿真程序

目录 1.算法描述 2.仿真效果预览 3.Verilog核心程序 4.完整FPGA 1.算法描述 整个模型的基本框图为 软件无线电是现代通信技术的重要研究领域和发展方向,目前发展迅速.快速发展的软件无线电技术与落后的硬件计算资源之间的矛盾越来越突出.为了缓解这个矛盾,一方面可以加快集…

职场日常:一文剖析性能测试流程,时间为啥那么长?

如果你做过性能测试,你就会知道,性能测试的时间要比功能测试时间长很多,但是,你没有做过,你可能就会问了,为什么性能测试时间要长那么多呢?今天就用一文,带大家了解性能测试工作流程…