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. Java并发编程教程

    Java是一种多线程编程语言,我们可以使用Java来开发多线程程序. 多线程程序包含两个或多个可同时运行的部分,每个部分可以同时处理不同的任务,从而能更好地利用可用资源,特别是当您的计算机有多个CPU ...

  2. 免费服务器AWS免费使用一年详细教程

    AWS免费使用详细教程 福利,亚马逊AWS免费试用一年,简直是爽歪歪.无论是搭建网站,还是自建**,都是不错的选择.详细如下: 开始准备:信用卡一张. 详细视频教程见:http://v.youku.c ...

  3. 2019秋季学期第2周Java学习总结

    本周在第一周接触认识Java后对该编程语言有了进一步了解,明白了Java的类型:包括Application程序,Applet程序.知道了一个Java程序的关键字(public class).主方法(p ...

  4. CF986C

    CF986C 给\(A_i\)连一条向补集的边和子集的边,然后dfs求联通块数 #include<iostream> #include<cstring> #include< ...

  5. 备份一下我的.bash_aliases文件

    # 这是陈悦老师的课程练习目录 alias cdchen="cd /home/branches/Documents/chen" # 每次grep都显示出行号 alias grep= ...

  6. Python之字典推导式

    推导式是个绝妙的东西,列表推导式一出,map.filter等函数黯然失色,自 Python2.7以后的版本,此特性扩展到了字典和集合身上,构建字典对象无需调用 dict 方法. bad numbers ...

  7. 防御 CSRF

    我还针对这个问题请教了 @c4605 , 他对防御 CSRF 提出了两种解决方案: 在每个表单中包含一个 CSRF Token.不将用于认证的 Token 或 Seesion ID 储存在 Cooki ...

  8. HTML + CSS (上)

    HTML 概念: 超文本标记语言. 核心: 语义. 主体结构: <!doctype html> //告诉浏览器这是什么语言 html //主体 head //头文件 body //页面主体 ...

  9. ASE——第一次结对作业

    ASE--第一次结对作业 问题定义 很早就听说了MSRA的黄金点游戏,让大家写Bot来参加比赛看谁的AI比较聪明可以操盘割韭菜.深感ASE课程老师设计的任务太用心了,各种接口都准备好了,大家只用专注于 ...

  10. RemoTing 搭建简单实现

    今天对C# Remoting进行了初步的学习,废话不说... RemotingModel: Talker.cs using System;using System.Collections.Generi ...