redis zset类型数据结构跳跃表

158 阅读2分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

8redis zset类型数据结构跳跃表

什么是跳跃表?

跳跃表是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。查找节点时间复杂度为O(logN),最坏O(N)

Redis只在两个地方用到跳跃表,一是实现有序集合键,另一个是在集群节点中用作内部数据结构

跳跃表节点的实现在redis.h中定义

/* ZSETs use a specialized version of Skiplists */
/*
 * 跳跃表节点
 */
typedef struct zskiplistNode {
    // member 对象
    robj *obj;
    // 分值
    double score;
    // 后退指针
    struct zskiplistNode *backward;
    // 层
    struct zskiplistLevel {
        // 前进指针
        struct zskiplistNode *forward;
        // 这个层跨越的节点数量
        unsigned int span;
    } level[];
} zskiplistNode;

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

跳跃表由跳跃节点构成,跳跃表中header和tail指针分别指向跳跃表的表头和表尾节点,通过这两个指针,程序定位表头节点和表尾节点的复杂度为O(1)

length记录节点数量,获取跳跃表长度时间复杂度为O(1)

level属性表示目前表内节点的最大层数

跳跃表节点的level数组中每个元素包含一个指向其他节点的指针,程序可以通过这些层来加快访问其他节点的速度,层的数量越多,访问其他节点的速度就越快

每次创建一个新跳跃表节点的时候,程序都会根据幂次定律随机生成一个介于1和32之间的值作为level数组的大小

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

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

同一个跳跃表中,多个节点可以包含相同的分值,但每个节点的成员对象必须是唯一的**,分值相同的节点按照成员对象在字典序中的大小进行排序**

总结

跳跃表是有序集合的底层实现之一

redis跳跃表由zskiplist和在zskiplistNode构成,zskiplist保存跳跃表信息,zskiplistNode表示跳跃表节点

跳跃表节点层高在1到32之间的随机数

同一跳跃表中分值可以相同,每个节点的成员对象必须是唯一的,节点按照分值大小排序,分值相同按成员对象在字典序中的大小排序。