美文网首页
Redis数据结构学习-跳表(四)

Redis数据结构学习-跳表(四)

作者: 牛牛_735d | 来源:发表于2020-04-27 20:28 被阅读0次

跳表

跳表 skiplist 是一种有序的数据结构, 通过在每个节点中维持多个指向其它节点的指针、达到快速访问节点的目的

支持平均 O(logN), 最坏 O(N)复杂度的查找, 还支持顺序性操作来批量处理节点, 大部分情况下、效率可以合平衡树相媲美, 且实现简单, 很多程序都可以使用skipList替代平衡树, Redis使用跳跃表作为有序集合键的底层实现之一.

跳表只在两个地方使用: 实现有序集合键 & 在集群节点中用作内部结构

跳表的实现

Redis 的跳跃表由 redis.h/zskiplistNoderedis.h/zskiplist 两个结构定义, zskiplistNode 结构用于表示跳跃表节点, zskiplist 则用于保存跳跃表节点的相关信息, eg.

节点梳理、及指向表头节点 和 表尾节点的指针.

跳表示意图.png

最左边是跳表的zskiplist结构, 包含下边这些属性:

header: 指向跳表的表头节点

tail: 指向跳表的表尾节点

level: 记录当前跳表内、层次最大的那个节点的层数(表头节点的层数不计算在内)

length: 记录跳表的长度, 即: 目前跳表内包含的节点的数量(表头节点不计)

右边是4个zskiplistNode结构, 属性如下:

level: 节点中用 L1, L2, L3 等标记节点的各个层, L1代表第一层, 依次类推. 每个层有两个属性: 前进指针跨度. 前进指针用于访问位于表尾方向的其它节点, 跨度记录前进指针指向的节点和当前节点的距离. 程序从表头向表尾遍历时, 访问会沿着层的前进指针进行.

backward: 后退指针, 节点中BW标记的指针, 指向当前节点的前一个指针, 后退指针在程序从表尾向表头遍历时使用

score: 分值, 节点中的1.0, 2.0, 3.0是各节点保存的分值, 在跳表中节点按各自保存的分值从小到大排列.

obj: 成员对象, 各个节点中的o1, o2 和 o3 是节点保存的成员对象.

注意: 表头节点和其它节点的构造是一致的, 也有后退指针, 分值 和 成员对象, 但不会被使用.

跳跃表节点

redis.h/zskiplistNode结构定义

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

跳跃表节点的level数组可以包含多个元素, 每个元素都包含一个指向其它节点的指针, 程序可以通过这些层来加速访问其它节点的速度, 一般来说、层的数量越多, 访问其它节点的速度就越快. 每次创建一个新的跳表时、程序根据幂次定律随机生成一个介于1和32之间的值作为level数组的大小, 即 层高

前进指针 每一个层都有一个指向表尾方向的前进指针(level[i].forward), 用于从表头向表尾方向访问节点.

跨度 (level[i].span)用于记录两个节点之间的距离, 两个节点之间的跨度越大,相距就越远. 指向null的所有前进指针的跨度都为0, 因为他们没有连向任何节点

后退指针 (backward)用于从表尾向表头方向访问节点, 跟一次可以跳多个节点的前进指针不同, 每个节点只有一个后退指针、只能后退至前一个节点.

分值和成员 (score)是一个double类型的浮点数, 跳跃表中所有的节点都按分值从小到大来排序(obj)是一个指针、指向一个字符串对象、字符串对象中则保存着一个SDS

在同一个跳表中、各节点保存的成员对象必须是唯一的、但多个节点保存的分值却是可以相同的. 分值相同的节点按照成员对象在字典序中的大小排序, 小的节点放在前边.

跳跃表

仅靠多个跳跃表节点就可以完成一个跳表、但使用一个zskiplist结构来持有这些节点, 程序可以更方便的对整个跳表进行处理, eg. 快速访问跳表的头结点和尾结点、快速获取节点数量.

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

headertail 指针分别指向表头和表尾节点, 程序定位表头节点和表尾节点的复杂度是 O(1)

通过length属性记录节点的数量、程序可以在 O(1) 复杂度内返回跳表长度

level 属性则用于在 O(1)复杂度内获取跳表中层高最大的节点的层数量(表头节点的层高不计)

重点回顾

  1. 跳表是有序集合的底层实现之一
  2. Redis的跳表实现由 zskiplistzskiplistNode 两个结构组成, 其中 zskiplist 用于保存跳表信息(eg. 表头节点、表尾节点、长度)、而zskiplistNode 则用于表示跳跃表节点
  3. 每个跳跃表节点的层高都是 1~32 之间的随机数
  4. 同一个跳表中、多个节点可以包含相同的分值、但每个节点的成员对象必须是唯一的
  5. 跳表中的节点按照分值大小排序、分值相同时、节点按照成员对象的大小排序

相关文章

  • 【算法打卡60天】Day36跳表:为什么Redis一定要用跳表来

    Day36学习内容 :跳表:为什么Redis一定要用跳表来实现有序集合?跳表是一种动态数据结构,实现灵活,可以通过...

  • 定时器实现 & 红黑树,跳表

    跳表:是为一个有序的链表建立多级索引的数据结构叫做跳表。redis中zset数据量大时底层数据结构使用跳表。 re...

  • Redis深度历险-跳表

    Redis深度历险-跳表 跳表是一个比较经典的数据结构,非常有用但又不像红黑树那么复杂,非常值得学习;在Ridis...

  • Redis数据结构学习-跳表(四)

    跳表 跳表 skiplist 是一种有序的数据结构, 通过在每个节点中维持多个指向其它节点的指针、达到快速访问节点...

  • 2.跳表的基本实现和特性

    一、跳表 跳表的设计与实现为啥 redis 使用跳表(skiplist)而不是使用 red-black redis...

  • 数据结构 - 跳表skiplist

    更多数据结构内容,请参考:数据结构 - 概要 简介 漫画算法:什么是跳跃表? Redis 为什么用跳表而不用平衡树...

  • 跳表SkipList

    因为这个周末加班,一直没有更新,实属抱歉,今天,我们来聊一聊一个数据结构,跳表。跳表是redis的一个核心组件,也...

  • redis数据结构--跳表

    跳表实质是链表,通过维护多个指向其他节点的指针,达到快速访问节点的目的。跳表查找的时间复杂度平均情况下是O(log...

  • 有关跳跃表的干货都在这里

    跳表的数据结构 跳表全称叫做跳跃表,简称跳表。跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。...

  • HBase内存管理之MemStore

    基于跳表实现的MemStore基础模型 实现MemStore模型的数据结构是SkipList(跳表),跳表可以实现...

网友评论

      本文标题:Redis数据结构学习-跳表(四)

      本文链接:https://www.haomeiwen.com/subject/wyauwhtx.html