跳跃表

134 阅读2分钟

简介

跳跃表是一种有序的数据结构,在每个节点维护多个执行其他节点的指针,从而达到快速到底查询节点的目的。在大部分情况下性能不比平衡树差,并且相对简单,因此很多程序都使用跳表替代平衡树。

结构

image.png

如图所示,跳跃表主要有一个zskiplist 和 多个zskiplistNode构成。

zskiplist结构的定义如下:

typedef struct zskiplist {
    //表 头 节点 和 表 尾 节 点
    structz skiplistNode *header, *tail;
    // 表中节点的数量
    uns ignedl ong length;
    // 表中层数最大的节点的层数 
    int level;
} zskiplist;

zskiplistNode结构定义:

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

跳跃表节点属性

1. 层

  • 跳跃表节点的level数组可以包含多个元素,每一个元素指向一个节点,level的元素越多,查找速度就越快。
  • 初始化跳跃表节点的时候,redis会根据幂等定律(越大的数值生成的概率越小)生成一个介于1-32 的数值作为跳跃表的level数组的大小。

2. 前进指针

level数值的对象中有一个前进指针,指向其他节点,通过前进指针可以遍历整个跳跃表。下面是一个遍历整个跳跃表的case,虚线表示实际走的前进指针:

image.png

3. 跨度

是指当前节点到其他节点直接经过了几个节点,主要是用于排位的计算,举个例子

image.png

我们在查找o3的时候经过了一个跨度为3的层,因此o3的排位为3。

4. 后退指针

与前进指针想法,后退指针是进行回退操作的指针。不同的是后退指针只有一个,只能回退到上一个节点

5. score 和 obj

socre是一个浮点数字段,跳跃表会根据score大小进行排序。而节点的obj对象是直接指向一个字符串对象,而字符串对象则保存着一个SDS值

跳跃表

  • head 和 tail 指向跳跃表的第一个节点和最后一个节点,可以快速定位头节点和尾节点
  • length 标识跳跃表的长度,但是不能超过一定长度
  • level属性表示跳跃表节点层最高的level数组的长度

参考: 《Redis 设计与实现》黄健宏 著