美文网首页
redis 内部数据结构(1.4)-跳跃表

redis 内部数据结构(1.4)-跳跃表

作者: 颜灏_2181 | 来源:发表于2017-04-07 11:26 被阅读0次
跳跃表示意图

位于图片最左边的是 zskiplist 结构, 该结构包含以下属性,右边是各个跳跃表节点
左边的zskiplist结构包括了一下几个属性:

  • header :指向跳跃表的表头节点。
  • tail :指向跳跃表的表尾节点。
  • level :记录目前跳跃表内,层数最大的那个节点的层数(表头节点的层数不计算在内)。2^5=32
  • length :记录跳跃表的长度,也即是,跳跃表目前包含节点的数量(表头节点不计算在内)。

位于 zskiplist 结构右方的是四个 zskiplistNode 结构, 该结构包含以下属性:

  • 层(level):节点中用 L1 、 L2 、 L3 等字样标记节点的各个层, L1 代表第一层, L2 代表第二层,以此类推。每个层都带有两个属性:前进指针和跨度。前进指针用于访问位于表尾方向的其他节点,而跨度则记录了前进指针所指向节点和当前节点的距离。在上面的图片中,连线上带有数字的箭头就代表前进指针,而那个数字就是跨度。当程序从表头向表尾进行遍历时,访问会沿着层的前进指针进行。
  • 后退(backward)指针:节点中用 BW 字样标记节点的后退指针,它指向位于当前节点的前一个节点。后退指针在程序从表尾向表头遍历时使用。
  • 分值(score):各个节点中的 1.0 、 2.0 和 3.0 是节点所保存的分值。在跳跃表中,节点按各自所保存的分值从小到大排列。
  • 成员对象(obj):各个节点中的 o1 、 o2 和 o3 是节点所保存的成员对象。

跳跃表节点

节点的结构体

typedef struct zskiplistNode {

    // 后退指针
    struct zskiplistNode *backward;

    // 分值
    double score;

    // 成员对象
    robj *obj;

    // 层
    struct zskiplistLevel {

        // 前进指针
        struct zskiplistNode *forward;

        // 跨度
        unsigned int span;

    } level[];

} zskiplistNode;

跳跃表节点的 level 数组可以包含多个元素, 每个元素都包含一个指向其他节点的指针, 程序可以通过这些层来加快访问其他节点的速度,一般来说, 层的数量越多, 访问其他节点的速度就越快。每次创建一个新跳跃表节点的时候, 程序都根据幂次定律 (power law,越大的数出现的概率越小)随机生成一个介于 1 和 32 之间的值作为 level 数组的大小, 这个大小就是层的“高度”。图 5-2 分别展示了三个高度为 1 层、 3 层和 5 层的节点, 因为 C 语言的数组索引总是从 0 开始的, 所以节点的第一层是 level[0], 而第二层是 level[1], 以此类推。

带有不同层高的节点

前进指针

每个层都有一个指向表尾方向的前进指针(level[i].forward 属性), 用于从表头向表尾方向访问节点。
图 5-3 用虚线表示出了程序从表头向表尾方向, 遍历跳跃表中所有节点的路径:

  • 迭代程序首先访问跳跃表的第一个节点(表头), 然后从第四层的前进指针移动到表中的第二个节点。
  • 在第二个节点时, 程序沿着第二层的前进指针移动到表中的第三个节点。
  • 在第三个节点时, 程序同样沿着第二层的前进指针移动到表中的第四个节点。
  • 当程序再次沿着第四个节点的前进指针移动时, 它碰到一个 NULL , 程序知道这时已经到达了跳跃表的表尾, 于是结束这次遍历。
Paste_Image.png

后退指针

前进指针可以跳跃,后退指针只能每次退回一层。

分值和成员

节点的分值(score 属性)是一个 double 类型的浮点数, 跳跃表中的所有节点都按分值从小到大来排序。

节点的成员对象(obj 属性)是一个指针, 它指向一个字符串对象, 而字符串对象则保存着一个 SDS 值。

在同一个跳跃表中, 各个节点保存的成员对象必须是唯一的, 但是多个节点保存的分值却可以是相同的: 分值相同的节点将按照成员对象在字典序中的大小来进行排序, 成员对象较小的节点会排在前面(靠近表头的方向), 而成员对象较大的节点则会排在后面(靠近表尾的方向)。

举个例子, 在图 5-7 所示的跳跃表中, 三个跳跃表节点都保存了相同的分值 10086.0 , 但保存成员对象 o1 的节点却排在保存成员对象 o2和 o3 的节点之前, 而保存成员对象 o2 的节点又排在保存成员对象 o3 的节点之前, 由此可见, o1 、 o2 、 o3 三个成员对象在字典中的排序为 o1 <= o2 <= o3 。

跳跃表

使用一个 zskiplist 结构来持有这些节点, 程序可以更方便地对整个跳跃表进行处理, 比如快速访问跳跃表的表头节点和表尾节点, 又或者快速地获取跳跃表节点的数量(也即是跳跃表的长度)等信息。
zskiplist 结构的定义如下:

typedef struct zskiplist {

    // 表头节点和表尾节点
    struct zskiplistNode *header, *tail;

    // 表中节点的数量
    unsigned long length;

    // 表中层数最大的节点的层数
    int level;

} zskiplist;

header 和 tail 指针分别指向跳跃表的表头和表尾节点, 通过这两个指针, 程序定位表头节点和表尾节点的复杂度为 O(1) 。通过使用 length属性来记录节点的数量, 程序可以在 O(1) 复杂度内返回跳跃表的长度。level 属性则用于在 O(1)复杂度内获取跳跃表中层高最大的那个节点的层数量, 注意表头节点的层高并不计算在内。

跳跃表在redis中用于实现有序集合
关于跳跃表的增删改查demo可以看这个http://blog.csdn.net/ict2014/article/details/17394259

相关文章

  • redis 内部数据结构(1.4)-跳跃表

    位于图片最左边的是 zskiplist 结构, 该结构包含以下属性,右边是各个跳跃表节点左边的zskiplist结...

  • Redis 跳跃表(skiplist)

    Redis基础类型中的有序集合、集群节点的内部数据结构用到了跳跃表(skiplist)。 5.1 跳跃表的实现 图...

  • Redis设计与实现-笔记(二)

    数据结构与对象 跳跃表 跳跃表是有序集合的底层实现之一, 除此之外它在 Redis 中没有其他应用。 Redis ...

  • redis基本数据结构

    redis 基本数据结构. redis的基本数据结构主要有: SDS动态字符串,链表,字典,哈希表,跳跃表,整数集...

  • 4.8-Redis6数据结构之SortedSet类型介绍和跳跃表

    Redis6数据结构之SortedSet类型介绍和跳跃表介绍 简介:Redis6数据结构之SortedSet类型介...

  • redis笔记

    redis基础知识 数据结构 底层数据结构 SDS 双向链表 压缩列表 跳跃表 Hash表 整数数组 对外数据结构...

  • 用Python深入理解跳跃表原理及实现

    最近看 Redis 的实现原理,其中讲到 Redis 中的有序数据结构是通过跳跃表来进行实现的。第一次听说跳跃表的...

  • Redis数据结构——跳跃表

    前言 跳跃表是一种有序的数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。这么说...

  • redis数据结构

    redis数据结构列表:简单动态字符串(sds)链表(list)字典(dict)跳跃表(skiplist)整数集合...

  • Redis 源码研究之skiplist

    本文主要记录Redis源码中skiplist数据结构的一些函数实现。 建议阅读: 1、Redis中跳跃表的理论说...

网友评论

      本文标题:redis 内部数据结构(1.4)-跳跃表

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