数据库
首页 > 数据库> > Redis 原理 - Sorted Set (ZSet)

Redis 原理 - Sorted Set (ZSet)

作者:互联网

Sorted Set (ZSet) 数据结构

使用 ziplist 图解

zset_ziplist_数据结构.png

使用 skiplist 图解

skiplist 定义

跳表是一种数据结构。它使得包含n个元素的有序序列的查找和插入操作的平均时间复杂度都是 O(logn),优于数组的 O(n)复杂度。快速的查询效果是通过维护一个多层次的链表实现的,且与下面一层链表元素的数量相比,每一层链表中的元素的数量更少。

skiplist 数据结构

//跳跃表节点
typedef struct zskiplistNode {
    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;

//有序集合
typedef struct zset {
    dict *dict; // 字典,键为成员,值为分值, 用于支持 O(1) 复杂度的按成员取分值操作
    zskiplist *zsl; // 跳跃表,按分值排序成员, 用于支持平均复杂度为 O(log N) 的按分值定位成员操作, 以及范围操作
} zset;

skiplist 图解

skiplist.jpg

简单说下skiplist的查找过程:

比如查询 分数比 broadm 小的用户名

  1. 使用zset中的字典dict快速获取broadm节点对应的score=4
  2. 从header节点的最高层(第5层)出发,最高层(第5层)的前进节点是 obj:mike score:3,对比发现,此节点的score=3, 小于要查询的节点的score=4 (说明目标节点在此节点的右边), 应该继续前进, 但是此节点没有前进节点了, 那就降低一层,直到找到有前进节点的层为止(这里是第2层)
  3. 第2层的前进节点就是 broadm 了,找到了
  4. 因为skiplist是有序的,并且每个节点都保存了 backward 指针, 所以直接遍历链表就可以获取分数比broadm小的节点了

这里的数据量比较少,不容易看出来效果, 当数据量很大的时候,这种查询是非常高效的,平均时间复杂度为 O(logn),基本和平衡二叉树等效

Redis使用skiplist而不是红黑树的原因?

标签:Set,struct,ZSet,ziplist,Redis,skiplist,复杂度,节点
来源: https://www.cnblogs.com/broadm/p/16424133.html