Redis数据结构-SkipList(跳表)

Redis数据结构-SkipList(跳表)

SkipList(跳表)首先是链表,但与传统链表相比有几点差异:
元素按照升序排列存储
节点可能包含多个指针,指针跨度不同。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jJYvbpTG-1666106485250)(.\原理篇.assets\1653986771309.png)]

查找19时

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rorA6ARZ-1666106485252)(C:\Users\wu\AppData\Roaming\Typora\typora-user-images\image-20221018231929942.png)]

可见效率会比较高。

SkipList(跳表)首先是链表,但与传统链表相比有几点差异:
元素按照升序排列存储
节点可能包含多个指针,指针跨度不同。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XxvHkStS-1666106485253)(.\原理篇.assets\1653986813240.png)]

SkipList(跳表)首先是链表,但与传统链表相比有几点差异:
元素按照升序排列存储
节点可能包含多个指针,指针跨度不同。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aRfLnawi-1666106485253)(.\原理篇.assets\1653986877620.png)]

小总结:

SkipList的特点:

  • 跳跃表是一个双向链表,每个节点都包含score和ele值
  • 节点按照score值排序,score值一样则按照ele字典排序
  • 每个节点都可以包含多层指针,层数是1到32之间的随机数
  • 不同层指针到下一个节点的跨度不同,层级越高,跨度越大
  • 增删改查效率与红黑树基本一致,实现却更简单
Redis 中的 skiplist(跳跃列表)是一种有序数据结构,它通过构建多层索引的方式提高了查找效率,从而能够在对数时间内完成插入、删除和搜索操作。Redis 使用 skiplist 来实现有序集合(zset),以支持高效地按分值排序以及范围查询。 ### skiplist 的基本结构 skiplist 是一种链表结构,但它通过在链表的基础上添加多层索引,使得查找效率从普通链表的 O(n) 提升到平均 O(log n)。每一层都是一个跳表,上层节点是下层节点的子集,通过这种方式可以快速跳过大量节点,从而加速查找过程。 在 Redis 中,skiplist 被实现为一个带有多个层级的节点结构。每个节点包含以下部分: - **前向指针(forward)**:指向当前层级的下一个节点。 - **跨度(span)**:表示从当前节点跳到下一个节点之间跨越的节点数。 - **后向指针(backward)**:用于从后向前遍历。 - **成员(ele)**:存储字符串类型的成员值。 - **分值(score)**:用于排序的数值。 Redisskiplist 的节点结构定义如下: ```c typedef struct zskiplistNode { sds ele; // 存储成员值 double score; // 分值 struct zskiplistNode *backward; // 后向指针 struct zskiplistLevel { struct zskiplistNode *forward; // 前向指针 unsigned long span; // 跨度 } level[]; } zskiplistNode; ``` Redisskiplist 最多支持 64 层索引,并且每一层的跳跃概率设置为 1/4,即每四个节点中大约有一个节点会上升到下一层[^4]。 ### skiplist 的实现特点 Redisskiplist 在经典跳表的基础上进行了一些优化和调整,以更好地支持有序集合的功能需求: - **支持重复分值**:在 Redisskiplist 中,多个节点可以拥有相同的 `score` 值,此时它们会按照 `ele` 字典序进行排序。 - **双向链表支持**:每个节点都有一个 `backward` 指针,允许从后向前遍历,这在实现范围查询时非常有用。 - **跨度(span)机制**:每个层级的 `span` 字段记录了当前节点到下一个节点之间的节点数量,这使得可以在不遍历整个链表的情况下快速计算出两个节点之间的距离。 - **内存优化**:Redis 在有序集合的实现中,当集合中的元素数量较少且元素值较小时,会使用 ziplist(压缩列表)来替代 skiplist,以节省内存。当元素数量或大小超过一定阈值时才会切换为 skiplist[^3]。 ### skiplistRedis 有序集合中的作用 Redis 的 zset(有序集合)是通过 skiplist 和 hash 表共同实现的: - **hash 表**:用于存储 member 和 score 的映射关系,确保每个 member 唯一,并能以 O(1) 的时间复杂度进行 member 的插入、删除和查找。 - **skiplist**:用于维护 member 按照 score 排序的顺序,支持高效的范围查询(如 ZRANGE、ZRANGEBYSCORE)和排名查询(如 ZRANK)[^2]。 这种复合结构使得 Redis 的 zset 既能保证快速的插入和查询操作,又能高效地处理排序和范围相关的请求。 ### skiplist 的算法分析 经典的 skiplist 的查找、插入和删除操作的平均时间复杂度为 O(log n),最坏情况下为 O(n)(当所有节点都在同一层时)。Redisskiplist 实现也继承了这一特性。 查找操作从最高层开始,逐层向下查找,直到找到目标节点或确定目标不存在。插入和删除操作则需要更新每一层的指针,并维护跨度信息。 Redis 在插入新节点时会通过随机算法决定节点的层数,以保证跳表的平衡性。具体来说,每个节点的层数是以概率 1/4 递减的方式生成的,即每上升一层的概率是前一层的 1/4,从而保证跳表的结构不会过于复杂[^4]。 ### skiplist 的应用场景 Redisskiplist 主要用于实现有序集合(zset),常见操作包括: - `ZADD`:添加一个或多个成员到有序集合中。 - `ZRANGE`:返回有序集合中指定排名范围内的成员。 - `ZSCORE`:获取成员的分值。 - `ZRANK`:获取成员在有序集合中的排名。 - `ZREM`:移除一个或多个成员。 这些操作的高效性得益于 skiplist 提供的对数时间复杂度的查找和插入能力。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值