Redis(4) —— 底层数据结构 —— skiplist(跳跃表)

如果一个有序集合包含的元素数量比较多,又或者有序集合中元素的成员(menber)是比较长的字符串时,Redis 就会使用 skiplist(跳跃表)来作为集合的底层实现

1. 跳跃表的用途

  1. 有序集合键(zset)
  2. 集群节点中用作内部数据结构


2. 跳跃表的特点

  1. 每个节点中存在多个指向其它节点的指针,以达到快速访问
  2. 平均 O(logn) 最坏 O(n) 复杂度的节点查询
  3. 效率和平衡树相媲美,但是实现比平衡树更简单


3. 跳跃表的结构

Redis 的跳跃表由 redis.h/zskiplistNode 和 redis.h/zskiplist 两个结构定义,其中 zskiplistNode 结构用于表示跳跃表节点,而 zskiplist 结构则表示用于表示跳跃表的相关信息

Redis(4) —— 底层数据结构 —— skiplist(跳跃表)_第1张图片

左边的 zskiplist 结构:

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

右边的 zskiplistNode 结构:

  • 层(level):图中 L1, L2 等表示层,每一层包含指向下个节点的指针和当前节点和指针所指向节点的跨度
  • 后退指针(BW):后退指针指向前一个节点,在反向遍历的时候使用
  • 分值(score):图中的 1.0 2.0 等表示分值,跳跃表按分值的从小达到排列
  • 成员对象(obj):图中的 o1,o2 等表示成员对象


4. 跳跃表的实现

跳跃表节点::
跳跃表节点的实现由 redis.h/zskiplistNode 结构定义:

typedef struct zskiplistNode{
    //后退指针
    strcut zskiplistNode *backward;
    
    //分值
    double socre;
    
    //成员对象
    robj *obj;
    
    //层
    struct zskiplistLevel{
        //前进指针
        struct zskiplistNode *forward;
        
        //跨度
        unsigned int span;
    }level[];
}zskiplistNode;
    • 跳跃表的 level 可以包含多个元素,level 包含的元素越多(层数越多),访问其它节点的速度就越快
    • 跳跃表创建一个节点时,会随机生成一个 1 到 32 之间的值作为 level 数组的大小
  1. 前进指针
    • 每一层都有一个前进指针,越上层的前进指针的所经过的跨度就越大
  2. 跨度
    • 跨度表示两个节点之间的距离
    • 跨度与节点的遍历没有关系,遍历只需要用前进指针就可以实现
    • 跨度实际上是用来排位(Rank)的,在查找某个节点过程中,所经历的跨度加起来就是该节点的排位
  3. 后退指针
    • 后退指针指向前一个节点,第一个节点的后退指针为 NULL
    • 后退指针用来进行倒序遍历
  4. 成员和分数
    • 分值时一个 double 类型的数据,跳跃表是按照分值从小到大排序
    • 节点的成员对象(obj属性)是一个指针,指向一个字符串对象,对象里面存放着 SDS 值
    • 在排序时,如果两个节点的分值一样,那么成员对象小的排在前面,大的排在后面


**跳跃表:** 跳跃表由 zskiplist 结构来实现
typedef struct zskiplist{
    //表头节点和表尾节点
    struct skiplistNode *header, *tail;
    
    //表中节点数量
    unsigned long length;
    
    //表中层数最大的节点的层数
    int level
}


## 参考资料 [1].《Redis 设计与实现》

你可能感兴趣的:(Redis)