Redis ZSet 底层skiplist是如何设计与实现的

跳表是一种通过增加多级索引来实现快速查找的链表结构,其查找时间复杂度可降至O(logn)。在跳表中,每个节点随机拥有多个层级,使得查找过程能进行二分查找。插入和删除节点时,由于随机分配层数,不需要严格平衡,简化了操作。这种数据结构常用于Redis等数据库系统中,以提高查找效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

跳表是空间换时间, 这是毋庸置疑的

skiplist 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。

为什么说 skiplist 是二分查找的链表

  • 首先看一下链表的结构

 

 

链表一般和数组作比较, 链表插入和删除的时间复杂度是O(1), 为什么说是O(1)呢, 因为链表在内存中是不连续的, 插入只对两个元素又影响, 但是链表也有痛处, 就是链表不能随机访问, 因为他的内存不连续(没有扩容的问题)所以必须有向前后元素位置的指针, 会消耗更多的内存. 数据出入和删除的时间复杂度是O(n), 为什么? 因为数据在内存中是一块连续的空间(扩容的时候也是找到1.5倍的空间把之前的复制过去), 所以插入和删除元素会影响后面的元素, 集体往后移位或者往前移位, 数据也有他的优势, 虽然数据查询的时间复杂度也是O(n), 但是数据可以通过索引来随机访问.

  • skiplist 是如何实现二分查找的链表

刚才说了链表的查找时间复杂度是O(n), 如果可以二分查找, 时间复杂度直接降为O(log n), skiplist 是这样解决的, 在链表的基础上增加了几层索引(redis 默认是32层), 这是链表就变成这样了

这样就变成了二分查找了, 这时候问题来了, 如何插入和删除一个节点, 是不是要rebalance?

  • skiplist 是如何解决rebalance

skiplist不要求上下相邻两层链表之间的节点个数有严格的对应关系,而是为每个节点随机出一个层数, 现在结构就成这样了

  • skiplist 是如何删除一个节点或者插入一个节点的呢

其实和链表的插入是一样的, 只不过skiplist 的前驱有很多个, 也是先修改前驱节点的后驱节点的前驱, 在修改前驱节点的后驱, 如果新增的节点的level比较高, 那么整体skiplist的level也要增高

删除也一样, 如果删除的节点level比较高, 那么有可能会降低整体的level

具体源码参照这篇文章 http://cmsblogs.com/?p=4430

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值