Redis中的有序集合

news2024/11/19 7:36:12

前言

本文着重介绍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/898472.html

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

相关文章

【深入了解PyTorch】PyTorch实战项目示例:深入探索图像分类、目标检测和情感分析

【深入了解PyTorch】PyTorch实战项目示例:深入探索图像分类、目标检测和情感分析 PyTorch实战项目示例:深入探索图像分类、目标检测和情感分析项目一:图像分类数据集准备构建模型训练模型模型评估和预测项目二:目标检测数据集准备构建模型训练模型模型评估和预测项目三:情…

记录因暴露阿里最高权限的Accesskey和secretKey导致的反弹shell攻击过程

Accesskey和SecretKey的泄露的原因 说到这个最高权限的key的泄露&#xff0c;绝对是低级的设计导致的。为了减少服务端的压力&#xff0c;直接让app直连oss服务&#xff0c;而且把最高权限的Accesskey和secretKey 下发到客户端&#xff0c;那么结果就是只要安装了该app的人&am…

js判断用户当前网络状态和判断网速

前端判断用户当前网络状态和判断网速 一、第一种是通过 HTML5 提供的 navigator 去检测网络(1)、原理介绍:(2)、兼容性 二、监听window.ononline和window.onoffline事件:三、通过ajax进行请求判断(兼容性好-推荐)(1)、原理介绍:(2)、注意: 四、navigator.connection方法监听网络…

PP-TS基于启发式搜索和集成方法的时序预测模型,使预测更加准确

时间序列数据在各行业和领域中无处不在&#xff0c;如物联网传感器的测量结果、每小时的销售额业绩、金融领域的股票价格等等&#xff0c;都是时间序列数据的例子。时间序列预测就是运用历史的多维数据进行统计分析&#xff0c;推测出事物未来的发展趋势。 为加快企业智能化转型…

Vue elementui 实现表格selection的默认勾选,翻页记录勾选状态

需求&#xff1a;当弹出一个列表页数据&#xff0c;对其进行筛选选择。 列表更新&#xff0c;填充已选数据 主要使用toggleRowSelection 代码如下&#xff1a; <el-table v-loading"loading" :data"drugList" selection-change"handleSelection…

安卓手机跑 vins slam (1)

一直是手机拍照&#xff0c;用RealityCapture重建三维模型。因为他是靠特征点去把拍摄的多个图像进行对齐的。需要拍摄的足够多&#xff0c;且有特征才能对齐&#xff0c;要不然会生成多个组件&#xff0c;还得手动拼。 而且重建的三维模型有尺度问题&#xff0c;自动重建的模…

四、内存管理

1、为什么需要自己实现内存管理 (1)RTOS涉及的内核对象&#xff1a;task、queue、semaphores和event group等。为了让FreeRTOS更容 易使用&#xff0c;这些内核对象一般都是动态分配&#xff1a;用到时分配&#xff0c;不使用时释放。使用内存的动态管理功能&#xff0c;简化了…

使用yolov5进行安全帽检测填坑指南

参考项目 c​​​​​​​​​​​​​​GitHub - PeterH0323/Smart_Construction: Base on YOLOv5 Head Person Helmet Detection on Construction Sites&#xff0c;基于目标检测工地安全帽和禁入危险区域识别系统&#xff0c;&#x1f680;&#x1f606;附 YOLOv5 训练自己的…

Unity导入google.protobuf失败,无法找到google命名空间

问题&#xff1a; 1.刚开始把protobuf的文件夹直接从其他项目里(unity2021)里复制到unity(2020)版本&#xff0c;当时报错protobuf.dll的依赖项system.memory版本不对。 2.没有使用原来的protobuf文件了。使用vs2019的NuGet管理包来下载Google.Protobuf &#xff0c;仍然报错找…

爬虫学得好,然后呢?最新Python人工智能就业班课程

课程链接&#xff1a; 私信&#xff1a;达内 课程介绍&#xff1a; 【达内最新Python人工智能就业班课程目录】 &#x1f4da; 1. Python核心 &#x1f9e0; 2. 面向对象程序设计 &#x1f52e; 3. Python高级 &#x1f4bb; 4. 阶段项目实战 &#x1f427; 5. Linux操作系…

PHP海外代购管理系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 海外代购管理系统是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 代码下载 https://download.csdn.net/download/qq_41221322/88229435 论文 https://…

python的全局解释锁(GIL)

一、介绍 全局解释锁&#xff08;Global Interpreter Lock&#xff0c;GIL&#xff09;是在某些编程语言的解释器中使用的一种机制。在Python中&#xff0c;GIL是为了保证解释器线程安全而引入的。 GIL的作用是在解释器的执行过程中&#xff0c;确保同一时间只有一个线程可以…

win11安装ubuntu 子系统安装过程及注意事项

第一步 &#xff1a;安装系统必须组件 由于子系统是系统自带组件&#xff0c;需要安装软件支持 第二步&#xff1a;应用商店安装 ubuntu 编辑 编辑 这个时候打开会报错 第三步&#xff0c;运行linux子系统 选择Windows PowerShell 以管理员身份运行&#xff09; 输入&#…

docker基础操作练习

目录 1.安装docker服务&#xff0c;配置镜像加速器 2.下载系统镜像&#xff08;Ubuntu、 centos&#xff09; 3.基于下载的镜像创建两个容器 &#xff08;容器名一个为自己名字全拼&#xff0c;一个为首名字字母&#xff09; 4.容器的启动、 停止及重启操作 5.怎么查看正在…

微信个人号二次开发过程、微信ipad协议

友情链接&#xff1a;geweapi.com 点击即可访问 大家好&#xff0c;今天给大家介绍下ipad的具体情况以及特点 傻瓜式API&#xff0c;掌握JAVA、Go、PHP、Python等任意一种后端代码&#xff0c;你就可以 通过API 搭建一个 微信机器人功能 &#xff0c;用来自动管理微信消息 我们…

常用curl参数及样例讲解

1 缘起 后端/后台项目开发过程中&#xff0c;有两个阶段的接口测试和验证&#xff0c;自测阶段&#xff0c;通过Postman构建请求&#xff0c; 自建一些参数&#xff0c;测试功能以及边界条件&#xff0c;这些都是可以自行掌控的&#xff0c;当完成功能验证与前端对接时&#x…

以创新点亮前路,戴尔科技开辟数实融合新格局

编辑&#xff1a;阿冒 设计&#xff1a;沐由 2023年&#xff0c;对于戴尔科技而言是特殊的一年&#xff0c;这是戴尔科技进入中国市场第25个年头——“巧合”的是&#xff0c;这25年也是中国产业经济发展最快&#xff0c;人们工作与生活发生变化最大的四分之一个世纪。 2023年&…

C# 观察者模式

一、概述 观察者模式是一种常用的设计模式&#xff0c;它属于行为型模式。在C#中&#xff0c;观察者模式通过定义一种一对多的依赖关系&#xff0c;使得当一个对象的状态发生变化时&#xff0c;所有依赖于它的对象都会得到通知并自动更新。这种模式可以实现松耦合&#xff0c;…

关键点检测中的对象关键点相似度

在不断发展的计算机视觉领域,理解物体的精确结构和姿态至关重要。无论是检测杂乱场景中的特定物体,还是实时分析人体姿势,关键点都起着至关重要的作用。对象上的这些独特点通常对应于角、边缘或其他可识别部分,用作识别和跟踪对象的锚点。但是我们如何衡量这些检测到的关键…

Java版本说明

java7 当谈到Java 7对应的JDK版本时&#xff0c;Java SE 7是Java 7的官方JDK版本。Java SE&#xff08;Standard Edition&#xff09;是Java平台的标准版本&#xff0c;它提供了Java编程语言的核心库和工具。 Java SE 7的JDK版本是JDK 7。你可以通过以下链接下载Java SE 7的J…