Redis的设计与实现 跳跃表

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,倚天版 1GB 1个月
简介: Redis的设计与实现 跳跃表

一 跳跃表概念

跳跃表是一个有序数据结构,他通过每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的,大部分情况下跳跃表的效率会和平衡树接近,但是他的实现简单,所以很多都使用了跳跃表,Redis使用跳跃表作为他的有序集合键(zset)的底层实现以及集群节点中用作内部的数据结构

二 数据结构

image.png

三 跳跃表的实现

Redis由zskiplistNode和zskiplist两个数据结构定义

  1. zskiplist

    他的数据结构

    image.png

    • header 指向跳跃表的表头节点
    • tail 指向跳跃表的表尾节点
    • level 记录跳跃表内层数最大的那个节点的层数
    • length 记录跳跃表节点的数量(表头节点不计入)
    • 代码

      typedef struct zskiplist {
      // 表头节点和表尾节点
      struct zskiplistNode header, tail;
      // 表中节点的数量
      unsigned long length;
      // 表中层数最大节点的层数
      int level;
      } zskiplist;

  2. zskiplistNode

    他的数据结构

    image.png

  • 层(对应L1 L2 L3...) 每个层包含两个属性,前进指针和跨度,前进指针用来访问表尾节点的其他节点,跨度用来记录前进指针所指向节点和当前节点的距离
  • 后退指针 节点中使用BW来标记后退指针,他指向当前节点的前一个节点,从表尾到表头遍历时使用
  • 分值 如图中,各个节点保存的1.0 2.0 3.0 就是各个节点的分值,节点按照各个保存的分值从大到小排列(这里保证了zset的有序)
  • 成员变量 节点中所保存的 o1 o2 o3 就是所保存的成员变量,比如

     
     jedis.zadd("myzset", 98, "tom1");
     jedis.zadd("myzset", 99, "peter");
     jedis.zadd("myzset", 33, "james");
     

    这里面"tom1"就是成员变量,98就是分值

  • 代码

      typedef struct zskiplistNode {  
          //成员变量
          robj *obj;  
          // 分值
          double score;  
          // 后退指针
          struct zskiplistNode *backward;  
          
          // 层
          struct zskiplistLevel {  
              // 前进指针
              struct zskiplistNode *forward;  
              
              // 跨度
              unsigned int span;  
          } level[];  
      } zskiplistNode;  
      

四 跳跃表的遍历及插入

  1. 遍历

    首先访问跳跃表表头节点,获取第一个元素L1,再通过L1去查找其他元素上的跨度最短的L1,如果找到了末尾,末尾的L1节点指向null那么遍历结束,得到L1的分值以及成员变量。

  2. 插入
    以依次插入50、7、25为例子

    • 初始化一个层数为1的节点
    • 插入50时,先通过一个函数生成一个随机数表示50占据的层数,即2。从顶层开始遍历,由于下一个节点为null,直接插入。
    • 比较层数,因为新节点有两层,那么我们需要将头节点的第二层指向新节点。并把当前层数更新为2。
    • 紧接着,插入7,同样通过一个函数生成一个随机数表示7占据的层数,这里为1。
    • 从顶层开始遍历,由于头部节点顶层指向50,7和50比较,可以得出7要插入的位置在头部到50这个位置,此时我们取得头部节点。
    • 由于从顶层位置开始找其,此时层数为第二层,而7这个节点只有一层,我们以取得的头部为出发点,从头部的第一层开始找起。
    • 由于第一层的头部节点指向50,7和50比较,再次得出7要插入的位置在头部到50这个位置。
    • 此时,比较7的层数和头部位置所在的层数(都是第一层),建立关联,将7和头部位置第一曾做关联,然后7的第一层指向50的第一层。
    • 由于7只有一层,遍历结束。
    • 同理,插入25,不过这里插入25后,由于25的节点有三层,比当前的最大层数2大,所以记得要更新当前最大层数。
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
存储 NoSQL Java
【Redis系列】那有序集合为什么要同时使用字典和跳跃表
面试官问:那有序集合为什么要同时使用字典和跳跃表来实现?我:这个设计主要是考虑了性能因素。1. 如果单纯使用字典,查询的效率很高是O(1),但执行类似ZRANGE、ZRNK时,排序性能低。每次排序需要在内存上对字典进行排序一次,同时消耗了额外的O(n)内存空间
【Redis系列】那有序集合为什么要同时使用字典和跳跃表
|
1月前
|
NoSQL Redis
Redis 中的跳跃表是什么?
Redis 中的跳跃表(Skiplist)是一种可以替代平衡树的数据结构,它主要用于实现有序集合(Sorted Set)功能。跳跃表通过在多个层级的链表上增加索引来提高查询效率,其效率可以与平衡树相媲美,但实现起来更简单。
21 1
|
1月前
|
消息中间件 存储 NoSQL
Redis数据结构—跳跃表 skiplist 实现源码分析
Redis 是一个内存中的数据结构服务器,使用跳跃表(skiplist)来实现有序集合。跳跃表是一种概率型数据结构,支持平均 O(logN) 查找复杂度,它通过多层链表加速查找,同时保持有序性。节点高度随机生成,最大为 32 层,以平衡查找速度和空间效率。跳跃表在 Redis 中用于插入、删除和按范围查询元素,其内部节点包含对象、分值、后退指针和多个前向指针。Redis 源码中的 `t_zset.c` 文件包含了跳跃表的具体实现细节。
|
1月前
|
存储 NoSQL Redis
Redis数据结构—跳跃表 skiplist
Redis数据结构—跳跃表 skiplist
|
3月前
|
存储 NoSQL Redis
你了解Redis中的跳跃表吗?
你了解Redis中的跳跃表吗?
|
11月前
|
存储 NoSQL Redis
今天终于知道 Redis 为什么要用跳跃表了
Redis 为什么会选择用跳表来实现有序集合呢? 为什么不用红黑树呢?学完今天的内容,你就知道答案了。
416 1
|
12月前
|
存储 机器学习/深度学习 NoSQL
|
存储 NoSQL 算法
Redis从入门到精通之答疑为什么ZSet使用跳跃表而不是平衡树、哈希表
有同学阅读了Redis从入门到精通章节中的《Redis从入门到精通之底层数据结构跳表 SkipList》向我提问Redis从入门到精通之答疑为什么ZSet使用跳跃表而不是平衡树、哈希表。今天就做一个解答
963 5
Redis从入门到精通之答疑为什么ZSet使用跳跃表而不是平衡树、哈希表
|
11月前
|
存储 NoSQL 算法
Redis中ZSet的底层数据结构跳跃表skiplist,你真的了解吗?
Redis中ZSet的底层数据结构跳跃表skiplist,你真的了解吗?
144 0
|
机器学习/深度学习 NoSQL API
Redis的设计与实现(4)-跳跃表
跳跃表 (skiplist) 是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。Redis 使用跳跃表作为有序集合键的底层实现之一。
64 2