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. yum常见问题

    --> Finished Dependency Resolution Error: Multilib version problems found. This often means that ...

  2. openstack部署安装

    OpenStack实战 准备环境 controller 10.0.0.11 compute1 10.0.0.31 常用服务端口 mariadb:3306 memcached:11211 消息队列:56 ...

  3. Cocos2d-x之Director

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. Director类简介 在Cocos2d-x-3.x引擎中,采用节点树形结构来管理游戏对象,一个游戏可以划分为不同的场景,一个场景又可以分 ...

  4. nmon 定时任务 监控资源

    nmon命令: # ./nmon  –f  -s 30 –c 100 说明:-f 以文件的形式输出,默认输出是机器名+日期.nmon的格式,也可以用-F指定输出的文件名,例如: # ./nmon_x8 ...

  5. os.fork()----linux

    fork() 函数,它也属于一个内建并 且只在 Linux 系统下存在. 它非常特殊普通的函数调用,一次返 回但是 fork() 调用一次,返回两次.因为操作系统自动把当前进程(称为父)复制了一份(称 ...

  6. Python列表推导式中使用if-else

    data_list=[] col=["a", "b", "c", "d"] jdata={"a":1 ...

  7. 18-python基础-字符串(1)

    1.字符串的定义 字符串就是一串字符,是编程语言中表示文本的数据类型. 在python中可以使用一对双引号“”或者一对单引号‘’定义一个字符串. 可以使用索引获取一个字符串中指定位置的字符,索引计数从 ...

  8. 【java】记录一下java的常用用法

    1.二维数组 public static void main(String[] args) { //定义 int a[][] = {{1,2,3},{4,5,6},{7,8,9}}; int [][] ...

  9. PowerPoint for Mac 中的键盘快捷方式汇总

    PowerPoint for Mac 中的键盘快捷方式介绍给大家,使用PowerPoint for Mac可以创建新颖别致的演示文稿通过漂亮的设计.丰富的动画.电影动作.3D 模型和图标传达你的想法. ...

  10. 【JZOJ6433】【luoguP5664】【CSP-S2019】Emiya 家今天的饭

    description analysis 首先可以知道不符合要求的食材仅有一个,于是可以容斥拿总方案数减去选不合法食材的不合法方案数 枚举选取哪一个不合法食材,设\(f[i][j]\)表示到第\(i\ ...