redis学习系列(六)--redis基础跳跃表的构造

看redis的时候第一次看见跳跃表这种数据结构,说实话,之前还真不知道有这么个结构,哎。。。。。。。。。。。


跳跃表其实也是一个链表,不过子啊实现上有点区别,也是由一个一个的Node组成,zskiplistNode是组成,zsklist则是保存了跳跃表节点的相关信息,例如节点的数量,头结点指针,尾节点指针。

redis学习系列(六)--redis基础跳跃表的构造

zskiplist

最左边的就是zskiplist结构:

header: 指向表头节点

tail: 指向表尾节点

lever: 记录跳跃表内,层级最大的那个节点的层级(表头节点的层级不计算在内)

length:记录跳跃表的长度,就是跳跃表包含的节点的数量(表头节点不在计算内)

zskiplistNode

右边的是四个zskiplistNode结构:

层(lever):节点中用L1,L2,L3等字样标记各个层,L1代表第一层,L2代表第二层,每层有两个属性:前进指针和跨度

前进指针:用于访问表尾方向的其他节点

跨度:记录了前进指针所指向节点和当前节点的距离

具体看上图:连线上带有数字的箭头就代表前进指针,而数字就是跨度

程序在从表头遍历想表尾遍历时,访问会沿着层的前进指针进行

后退指针:节点中用BW字样标记节点的后退指针,它指向位于当前节点的前一个节点,因此它在从表尾向表头遍历时使用。

分值:节点中保存的值 1.0 ,2.0, 3.0

成员对象:保存的成员对象,o1,o2,o3



zskiplistNode的构造

typedef struct zskiplistNode {

    // 后退指针
    struct zskiplistNode *backward;

    // 分值
    double score;

    // 成员对象
    robj *obj;

    // 层
    struct zskiplistLevel {

        // 前进指针
        struct zskiplistNode *forward;

        // 跨度
        unsigned int span;

    } level[];

} zskiplistNode;

跳跃表节点的lever数组可以包含多个元素,每个元素都包含一个指向其他节点的指针,程序就是通过这些指针实现快速访问

redis学习系列(六)--redis基础跳跃表的构造

前进指针:

每一层都会有一个前进指针,表名遍历的方向;

图5-3中用虚线表示出从表头向表尾的方向,遍历所有节点的路径。

  1.迭代程序首先访问跳跃表的第一个节点(表头),然后从L4的前进指针移动到表中的第二个节点

2.在第二个节点时,程序沿着第二层的前进指针移动到表中的第三个节点

3.在第三个节点时,程序同样沿着第二层的前进指针移动到表中的第四个节点。

4.当程序在第四个节点的前进指针移动时,会碰到一个null,此时已经到达了跳跃表的表尾,

redis学习系列(六)--redis基础跳跃表的构造

跨度

层的跨度用于记录两个节点之间的距离

1.两个节点之间的跨度越大,说明它们相隔的越远

2.指向null的所有前进指针的跨度为0,因为它们没有连上任何节点。

跨度是计算排位的: 排位是指在查找某个节点的过程中,将沿途访问过的所有层的跨度累计起来,得到的结果就是跳跃表中的排位。

下图例子中,虚线标注了在跳跃表中查找分值为3.0,成员对象为o3的节点时,沿途经历的层,由图可知只经历过一层,跨度为3

redis学习系列(六)--redis基础跳跃表的构造

后退指针

bw属性,用于表尾向表头访问节点时,与前进指针不同的是,每个节点只有一个后退指针,所以每次只能后退一个节点

图5-6表示的是从tail节点从表尾向表头遍历,直至遇到null节点,结束

redis学习系列(六)--redis基础跳跃表的构造

分值和成员

节点的分值都是按照分值大小从小到大来排序

节点的成员对象是一个指针,指向一个字符串对象,而字符串保存着一个SDS值。


在同一个跳跃表中,保存的成员对象是唯一的,但是分值确实可以相同的,分值相同的节点将按照在字典序中来排序,成员对象小的节点排在前面。

redis学习系列(六)--redis基础跳跃表的构造


zskiplist 结构的定义如下:

typedef struct zskiplist {

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

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

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

} zskiplist
头指针和尾指针定位表头和表尾,时间复杂度为O(1)