06 Redis 跳表详解

什么是有序集合

 

顺便一下set,上次我们说过,set也是使用dict实现,只不过value是null,所以不过多说了。言归正传,zset是redis中最具有特色的数据结构,类似于java中的SorteddSet和HashMap的结合,首先它有set不可重复的特性,在这个基础上,还可以给value赋予一个score(排序权重)。

那适合什么样的场景呢,举个栗子,可以实现一个书的榜单,value是书名,score是书的评分,如下。

> zadd books 9.0 "think in java"(integer) 1> zadd books 8.9 "java concurrency"(integer) 1> zadd books 8.7 "java cookbook"(integer) 1> zrange books 0 -1 # 根据score排序"think in java""java concurrency""java cookbook"> zrevrange books 0 -1 # 根据score逆序排序"java cookbook""java concurrency""think in java"> zcard books #count(integer) 3> zscore books "java concurrency"# score使用double存储,所以有精度问题"8.9000000000000004" > zrank books "java concurrency" # 排名(integer) 1> zrangebyscore books 0 8.91 # 根据分值遍历"java concurrency""java cookbook"> zrangebyscore books -inf 8.91 withscores # 根据分值区间查询 score小于等于8.911)"java cookbook"2)"8.59999999999999996" 3)"java concurrency"4)"8.9000000000000004" 

怎么实现有序集合

那么zset怎么实现的呢?zset底层是hash字典加上跳跃链表(skiplist)。上篇说过hash字典,这次主要说跳跃链表。直接上源码。​​​​​​​

/** * 有序集合结构体 */typedef struct zset {    /*     * Redis 会将跳跃表中所有的元素和分值组成      * key-value 的形式保存在字典中     * todo:注意:该字典并不是 Redis DB 中的字典,只属于有序集合     */    dict *dict;    /*     * 底层指向的跳跃表的指针     */    zskiplist *zsl;} zset;/** * 跳跃表结构体 */typedef struct zskiplist {    struct zskiplistNode *header, *tail;    unsigned long length;    int level;} zskiplist;/** * ZSETs use a specialized version of Skiplists * 跳跃表中的数据节点 */typedef struct zskiplistNode {    sds ele;// 具体value    double score;// 评分    struct zskiplistNode *backward;// 后退指针    struct zskiplistLevel {        // 前进指针        struct zskiplistNode *forward;        /**         * 跨度实际上是用来计算元素排名(rank)的,         * 在查找某个节点的过程中,将沿途访过的所有层的跨度累积起来,         * 得到的结果就是目标节点在跳跃表中的排位         */        unsigned long span;    } level[];    // 层} zskiplistNode;

这么看有点懵逼吧?直接上图。

层数怎么定义呢?

上源码。​​​​​​​

int zslRandomLevel(void) {    int level =1;    while((random()&0xFFFF)<(ZSKIPLIST_P * 0xFFFF))        level+= 1;    return (level<ZSKIPLIST_MAXLEVEL)?level:ZSKIPLIST_MAXLEVEL;}

每个新加入的节点都调用随机算法分配层数,redis的概率是25%,也就是ZSKIPLIST_P为25%。

查找过程

查找、更新、删除区别不大,就已查找举例了。

到这里基本就说完了,大家可以思考下,zset的元素排名怎么算出来的呢?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis 跳表(Skip List)是一种有序数据结构,用于实现有序集合(Sorted Set)的数据存储和快速查找。 跳表的核心思想是在链表的基础上增加多级索引,通过索引来加速查找。每一级索引包含一部分节点,这些节点按照某种规则连接起来,形成一个类似于二叉树的结构。每一级索引的节点数逐级减少,最高级索引只有两个节点,分别指向整个跳表的头节点和尾节点。 在跳表中,每个节点除了保存值之外,还保存了指向同一层级或下一层级的节点的指针。通过这样的结构,跳表可以在不需要遍历所有节点的情况下,快速定位到目标节点。 Redis 使用跳表实现有序集合的数据结构,具体实现步骤如下: 1. 创建一个带有头节点和尾节点的空跳表。 2. 向跳表中插入新的元素时,从最高级索引开始,逐级向下查找插入位置。 3. 在每一级索引中,找到插入位置后,将新节点插入到该位置后面。 4. 根据概率随机算法,决定是否在更高级索引中插入新节点的指针。 5. 删除元素时,从最高级索引开始,逐级向下查找并删除节点。 6. 如果删除节点后某一级索引只剩下头节点和尾节点,则删除该级索引。 通过使用跳表Redis 在有序集合中执行插入、删除、查找等操作的时间复杂度可以达到 O(logN),相比于传统的有序数组或平衡二叉树,跳表具有更高的效率和简单的实现方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值