[redis]redis系列四:跳跃表

跳跃表通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。跳跃表支持平均O(logN)、最坏O(N)复杂度的节点查找。

跳跃表的实现

跳跃表定义在server.h文件中,下图所示为一个跳跃表的示例:
[redis]redis系列四:跳跃表_第1张图片
上图中最左边的是zskiplist结构,右边四个是跳跃表节点(zskiplistNode结构),跳跃表的结构定义如下:

// 跳跃表节点
typedef struct zskiplistNode {
    sds ele;
    double score;
    struct zskiplistNode *backward;
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned long span;
    } level[];
} zskiplistNode;

各属性说明如下:

  • score:跳跃表节点的分值;
  • level:是一个数组,数组中每个元素有一个指向表结尾方向某个节点的指针(forward)和当前节点与forward节点的跨度(span),如上图所示,肩头上的数字表示跨度;
  • backward:后退指针,上图所示中BW字样标记节点的后退指针,它指向位于当前节点的前一个节点,后退指针在程序从表尾向表头遍历时使用;
  • ele:节点保存的成员对象(sds是char *);

zskiplist结构的定义如下:

typedef struct zskiplist {
    struct zskiplistNode *header, *tail;
    unsigned long length;
    int level;
} zskiplist;

各属性说明如下:

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

注:表头结点和其他节点构造是一样的,表头结点也有后退指针、分值和成员对象,不过表头结点的这些属性都不会用到

跳跃表从表头节点开始以跨度为1向表尾方向前进即可遍历整个跳跃表。跨度可以用来计算排位:在查找某个节点的过程中,将沿途访问过的所有层的跨度累计起来,得到的结果就是目标节点在跳跃表中的排位。

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

你可能感兴趣的:(redis)