Redis中,zset是一个复合结构:

  • 使用hash来存储valuescore的映射关系

  • 使用跳跃表来提供按照score进行排序的功能,同时可以指定score范围来获取value列表

结构

zset内部是一个hash字典加一个跳跃表skiplist

struct zslnode {
string value;
double score;
zslnode *[]forwards; // 多层连接指针
zslnode *backward // 回溯指针
} zslnode;

struct zsl {
zslnode *header; // 跳跃表头指针
int maxLevel; // 跳跃表当前最高层
map<string, zslnode*> ht; // hash结构的所有键值对
} zsl;

图为跳跃表示意图,实际上在Redis中共有64层,即最多可容纳2^64个元素。

每一个kv块即代码中zslnodeheadervalueNULL值,scoreDouble.MIN_VALUEkv之间使用指针链接成为双向链表,这些键值对根据score进行有序排列,不同的kv层高可能不同,层数越高则kv越少,同一层的kv之间使用指针进行串接,对于每一层的元素的遍历都是从kv header出发的。

常用操作

查找

如图所示,需要定位紫色的kv时,首先从header最高层开始进行遍历,遍历到第一个比k值小的节点,然后下降一层继续查找该层最后一个比k小的元素,依此类推,直到查找到该元素为止。

搜索时中间的一系列节点称之为搜索路径,它是从最高层一直到最底层的每一层最后一个比目标节点小的元素节点列表。

插入

插入新节点时,首先需要搜索合适的插入点,类似于查找过程找到合适节点之后就可以开始创建新的节点。创建时需要为节点随机分配一个层数,再将搜索路径上的节点和新节点通过前后指针进行串接。

如果分配的新的节点比当前跳跃表最大高度高的话,需要更新一下跳跃表的最大高度。

删除

删除过程和插入过程类似,需要先将搜索路径找出来,然后对于每一个层的相关节点,都需要重排一下前后指针,同时注意更新一下最高层数maxLevel

更新

调用zadd方法时,如果对应的value不存在,直接进行插入;如果已经存在且只是更新score的话,需要进行更新。

如果新值的score不会带来排序位置的改变,则不需要调整位置,直接修改元素的score值即可,否则需要调整该节点位置。

Redis在更新节点位置时,采用先删除这个元素,再插入这个元素的方法,这样就不需要判断是否需要调整位置,只需要进行两次路径搜索即可。

如果score值一样

极端情况下,zset中所有元素的score一样,此时查找性能也不会退化为O(n),因为zset的排序不只考虑score,如果score一样的话还会再比较value值。

计算元素排名

zset可以使用rank获取元素排名,主要是因为Redis中,对于skiplist的节点的forward指针进行了优化,给每一个forward指针添加了span属性,表示从前一个节点沿当前层的forward指针跳到当前节点时中间会跳过多少个节点。

借助span属性,在计算一个元素的排名时,只需要将搜索路径上经过的所有节点的span属性进行叠加即可计算出最终的rank值。

Redis数据结构之跳跃表-skiplist的更多相关文章

  1. Redis数据结构之跳跃表

    跳跃表是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的. 一.跳跃表结构定义1. 跳跃表节点结构定义: 2. 跳跃表结构定义: 示例: 二.跳跃表节点中各种 ...

  2. Redis数据结构:跳跃表

    1. 跳跃表是有序集合(zset)的底层实现之一: 2. 由zskiplist和zskiplistNode组成: 3. 每个跳跃表节点的层数都是1-32之间的随机数(每创建一个节点的时候,程序会随机生 ...

  3. redis 系列7 数据结构之跳跃表

    一.概述 跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的.在大部分情况下,跳跃表的效率可以和平衡树(关系型数据库的索引就是平衡树 ...

  4. Redis 的底层数据结构(跳跃表)

    字典相对于数组,链表来说,是一种较高层次的数据结构,像我们的汉语字典一样,可以通过拼音或偏旁唯一确定一个汉字,在程序里我们管每一个映射关系叫做一个键值对,很多个键值对放在一起就构成了我们的字典结构. ...

  5. redis源码分析之数据结构:跳跃表

    跳跃表是一种随机化的数据结构,在查找.插入和删除这些字典操作上,其效率可比拟于平衡二叉树(如红黑树),大多数操作只需要O(log n)平均时间,但它的代码以及原理更简单. 和链表.字典等数据结构被广泛 ...

  6. Redis 底层数据结构之跳跃表

    文章参考 <Redis 设计与实现>黄建宏 Redis(2) 跳跃表 跳跃表 跳跃表 skiplist 是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节 ...

  7. Redis 为什么使用跳跃表

    引言 跳跃表是一种有序的数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的. 什么是跳跃表 对于一个单链表来讲,即便链表中存储的数据是有序的,如果我们要想在其中查找某个 ...

  8. 存储系统的基本数据结构之一: 跳表 (SkipList)

    在接下来的系列文章中,我们将介绍一系列应用于存储以及IO子系统的数据结构.这些数据结构相互关联又有着巨大的区别,希望我们能够不辱使命的将他们分门别类的介绍清楚.本文为第一节,介绍一个简单而又有用的数据 ...

  9. redis 5.0.7 源码阅读——跳跃表skiplist

    redis中并没有专门给跳跃表两个文件.在5.0.7的版本中,结构体的声明与定义.接口的声明在server.h中,接口的定义在t_zset.c中,所有开头为zsl的函数. 一.数据结构 单个节点: t ...

随机推荐

  1. linux替换rm命令,防止误删

    1. 在/home/username/ 目录下新建一个目录,命名为:.trash 2.. 在/home/username/tools/目录下,新建一个shell文件,命名为: remove.sh #! ...

  2. redis的一些特性

    Redis内存回收 Redis复制原理 Redis提供的高可用方案 Redis提供的分片算法 Redis迁移

  3. Python运维-获取当前操作系统的各种信息

    #通过Python的psutil模块,获取当前系统的各种信息(比如内存,cpu,磁盘,登录用户等),并将信息进行备份 # coding=utf-8 # 获取系统基本信息 import sys impo ...

  4. RocketMQ事务性消息

    mq事务介绍 mq事务消息流程 生产者发送消息到mq,消息状态为:SEND_OK.此消息是消费者不可见(消费者无法消费此条消息) 执行本地任务:成功则返回COMMIT_MESSAGE,此时消费者可消费 ...

  5. Leetcode 200.岛屿的数量 - DFS、BFS

    Leetcode 200 岛屿的数量: DFS利用函数调用栈保证了检索顺序, BFS则需要自己建立队列,把待检索对象按规则入队. class Solution { // DFS解法,8ms/10.7M ...

  6. windows 添加永久路由

    打开cmd 命令为: route  add  目的网络    mask   子网掩码     下一跳   -p 添加完成后 可以使用如下命令进行查看: route print

  7. Codeforces 1148F Foo Fighters 贪心

    题意:给你若干个数对,每个数对有两个属性,一个属性是权值,一个属性是位标志,假设这些数对的的权值和是sum,你可以选择一个二进制数s,与所有的数对的位标志按位与,如果按位与之后的位标志有奇数个1,那么 ...

  8. 笔记63 Spring Boot快速入门(三)

    SpringBoot中使用JSP Springboot的默认视图支持是Thymeleaf,但是Thymeleaf还没开始学,熟悉的还是jsp,所以要让Springboot支持 jsp. 一.在pom. ...

  9. C++如何阻止一个类被实例化

    (1)定义一个无用的抽象函数,使得类成为抽象类 (2)将构造函数定义为private. 为什么要这样做? 一些工具类,没有被实例化的必要.

  10. 1、Python 基础类型 -- Number 数字类型

    一.Number