关于redis:Redis数据结构-跳跃表

2次阅读

共计 1286 个字符,预计需要花费 4 分钟才能阅读完成。

跳跃表

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

跳跃表是在有序链表的根底上实现的

在有序链表中,查找元素时,只能逐个查找,工夫复杂度为 O(N),操作非常迟缓。为了优化,能够思考在链表其中的元素上建索引的形式,就失去了链表。

跳跃表在 节点查问的工夫复杂度均匀为 O(logN),最坏状况下 O(N),还能够通过程序性操作来批量解决节点。

在大部分状况下,跳跃表的效率能够和均衡树相媲美,并且因为跳跃表的实现比均衡树要来得更为简略,所以有不少程序都应用跳跃表来代替均衡树。

Redis 应用 跳跃表作为有序汇合键的底层实现之一,如果一个有序列表蕴含的元素数量比拟多,又或者有序汇合中元素的成员是比拟长的字符串时,Redis 就会应用跳跃表来作为有序汇合键的底层实现。

Redis 只在两个中央用到了跳跃表,一个是实现有序汇合键,另一个是在集群节点中用作外部数据结构。

跳跃表的实现

跳跃表节点

typedef struct zskiplistNode {
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned int span;
    } level[];
    struct zskiplistNode *backward;
    double score;
    robj *obj;
} zskiplistNode;
  • level : 蕴含多个元素,每个元素都蕴含一个指向其它节点的指针,程序能够通过这些层来放慢拜访其它节点的速度,一般来说,层的数量越多,拜访其它节点的速度就越快;

    每次创立一个新跳跃表节点的时候,程序都依据幂次定律随机生成一个介于 1 和 32 之间的值作为 level 数组的大小,这个大小就是层的“高度”

    • forward : 每个层都有一个指向表尾方向的后退指针,用于从表头向表尾方向拜访节点。
    • span : 代表层的跨度,用于记录两个节点之间的间隔。两个节点之间的跨度越大,它们相距就越远;指向 null 的所有后退指针的跨度都为 0,因为它们没有连向任何节点。
  • backward : 节点的后退指针用于从表尾想表头方向拜访节点。跟能够一次跳过多个节点的后退指针不同,因为每个结点只有一个后退指针,所以每次只能后退至前一个节点。
  • score : 跳跃表的所有节点都按分值从小到大来排序。
  • obj : 是一个指针,指向一个字符串对象,而字符串对象则保留着一个 SDS 值。

在同一个跳跃表中,各个节点保留的成员对象必须是惟一的,然而多个节点保留的分值却是能够雷同的。分值雷同的节点将依照成员对象在字典序中的大小来进行排序,成员对象较小的节点会排在后面(凑近表头的方向),而成员对象较大的节点则会排在前面(凑近表尾的方向)。

跳跃表

typedef struct zskiplist {
    struct zskiplistNode *header, *tail;
    unsigned long length;
    int level;
} zskiplist;
  • header : 指向跳跃表的表头指针
  • tail : 指向跳跃表的表尾指针
  • length : 记录节点的数量
  • level : 记录跳跃表中层数最大的节点的层数
正文完
 0