Redis 有序集合数据结构 跳表

一. 跳表是一个怎样的数据结构

  跳表是能够让一个有序的链表实现二分查找的复杂度的结构,每一个节点至少有向右和向下的指针。最底下一层就是我们经常使用的链表,查询性能 O(N)。我们选择让这个链表的部分元素上升到上一层,每一个元素上升概率为 1/2(这个概率的取值类似于哈希表的负载因子 0.75,上升概率过大会导致数据冗余很多,虽然查询起来也更快,但是我们需要在空间和时间之间权衡),这样跳表的存储方式会让元素冗余多份在跳表不同的层级中,类似于哈希表的空间换时间的方式。跳表支持平均 O(logN) 的复杂度查询,可以通过顺序性来批量处理节点。这样的 复杂度和顺序性很容易让我们想到平衡树,其实这两者的查找方式和效率很相似,但是跳表的实现却比平衡树简单了很多,所以 Redis 中的有序集合也使用了跳表这样的结构
1. 最底下一层包含有这个集合的所有元素
2. 每一个元素有 1/2 的概率会上升到上一层。在保存元素的时候,生成一个随机数判断这个元素是否需要保存于上一层,这样的随机概率保证越上面元素个数越少,越往下节点数量呈 2 的倍数增加,上层元素数量少使查询跳跃更远,类似于二分查找
3. 跳表的层数是有限的,如下跳表只有三层,一般跳表不会超过 32 层,因为 32 层的跳表理论已经可以容纳几十亿的数据跳表示例
二. 跳表的增删改查
  1.增加节点 16
   1.从 head 开始,判断右方节点,发现 16 > 11,则指针右移
   2. 判断右方节点,发现右方为 null,则指针下移
   3. 判断右方节点,发现 16 < 20,则指针下移
   4. 判断右方节点,发现 16 < 20,则指针下移,发现下方指针为 null,则找到插入节点 16 的指针
   5. 新建 16 节点,将其加在 11 和 20 节点之间。查找结束条件,没有下方指针,且插入值在两个同层节点值之间
   6. 生成随机数,判断当前节点 16 是否上升一层,若上升,则加在上一层的 11 和 20 节点之间,上一层加完之后,重复步骤六。这里衍生出了一个问题,那就是如何找到上一层节点该插入的位置,我们肯定不应该从 Head 开始查找了,所以我们可以使用栈来将每次下移的节点存储,如果需要上升节点,就弹出来以便插入新节点之用,在这个示例中,栈中应该保存了上面两层的 11 节点增加节点的路径判断
  2.删除节点 11
   1.从 head 开始,判断右方节点,发现 11 = 11,则 Head 的 next 指针指向 节点 11 的 next,指针从 Head 的地方下移
   2. 判断右方节点,发现右方为 5,则指针右移
   3. 判断右方节点,发现 11 < 11,则节点 5 的next 指向节点 11 的 next,即节点 20,指针从节点 5 的地方下移
   4. 判断右方节点,发现 6 < 11,则指针右移。依次类推,直到到达节点 7
   5. 在节点 7 的位置上判断右方节点,发现 11 = 11,则节点 7 的next 指向节点 11 的 next。从节点 7 的位置下移,发现为 null,则完成删除

删除节点的路径判断
  3.查找节点 6
   1.从 head 开始,判断右方节点,发现 11 > 6,则指针从 Head 的地方下移
   2. 判断右方节点,发现右方为 5 < 6,则指针右移
   3. 判断右方节点,发现 11 > 6,则指针下移
   4. 判断右方节点,发现 6 = 6,则完成查找(PS:如果查找的是节点 11,那么第一步就可以完成查找。从这里就可以看出,查找节点不是一定需要到最下面一层的,但是增加和删除确实一定会到最底下一层的)

查找节点

参考文档:

  1. 跳表(skiplist)分析设计与实现(Java)
  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值