redis专题笔记 - 跳跃列表skiplist

数据结构

// 跳跃列表
struct zsl {
	zslnode* header;                // 跳跃列表的头结点
	int maxLevel;                   // 跳跃列表当前最高层
	map<string, zslnode*> ht;       // hash结构所有键值对;???不太理解干啥的
}

// 跳跃列表节点
struct zslnode {
	string value;                   // 节点值
	double score;                   // 节点分数
	zslforward*[] forwards;         // 向前跳跃节点指针列表
	zslnode* backward;              // 向后跳跃节点指针
}

// forward节点,封装了跳跃列表节点
struct zslfordward {
	zslnode* item;        
	long span;           // 增加跨度参数,用户快速计算节点的rank
}

跳跃列表的结构如下图所示:

在这里插入图片描述

  1. 图中每一个kv即是一个zslnode
    • 每一个zslnode有多个forwards(根绝当前kv的层高,图中-->),用于指向同层级下一个zslnode
    • 每一个zslnode仅有一个backward(图中<--),用于指向它前一个zslnode
  2. kv header是整个跳跃列表的头结点,它拥有最大层高,但不是真实数据节点,其节点value为NULL, score为Double.MIN_VALUE(最小值)
    • 跳跃列表的每一次查找都是从kv header开始的
  3. 跳跃列表的kv是有序的
    • 对于zset的存储而言,跳表是根据score排序

查找过程

假设现在要查找kv4这个节点:其查找过程如下:

  1. kv header的最高层开始,寻找当前层最后一个比kv4小的元素
    • 第四层下一个元素kv5已经大于kv4,所以第四层没有找到
  2. kv header下降一层,从第三层寻找最后一个比kv4小的元素
    • 找到kv3,此时跳到kv3再往后找
  3. kv3节点开始降一层(到第二层),寻找最后一个比kv4小的元素
    • 第二层下一个是kv5,比kv4大,查找失败
  4. kv3再降一层到第一层,此时只需要遍历第一层即可找到kv4

总结下来,跳跃列表的查找过程概括如下:

  1. kv header最高层,寻找当前层最后一个比目标元素小的kv temp
    • 找不到,则下降一层,继续寻找
    • 找到了,则跳到kv temp
  2. kv temp开始,下降一层,继续寻找当前层最后一个比目标元素小的kv,并重复第一步

插入过程

假设现在要在kv4kv5之间插入一个新元素kv4.5,其过程大致如下:

  1. 进行上述查找过程,找到kv4.5应该存放的位置
  2. 根据算法计算出kv4.5应该插入的层高level
    • 层高level使用随机算法生成,第一层的概率是50%,每高一层,概率下降50%,如level=2概率25%,level=3概率为12.5%
  3. 解开原kv4kv5之间的指针连接,分别与kv4.5各层连接
  4. 如果插入节点随机的层高大于当前跳跃表的最大层高,则需要更新跳跃表的最大层高

删除过程

  1. 通过查找过程找到要删除的kv
  2. 更新要删除kv各层的前向后向指针
  3. 如果影响最高层高,也要更新跳表最大层高

更新过程

单独跳跃表的更新,即是kv排序字段的值更新,存在两种情况:

  1. 排序字段值不影响跳表原有排序,则直接更新kv的排序字段值即可
  2. 如果影响跳表排序
    • 删除原kv
    • 重新插入kv

单独对跳表的更新理解起来比较抽象,这里还是使用有序集合zset的更新场景来说,假如zset有一个元素<value: golang score: 1.5>,这时由于某种原因,其值要变更为<value: golang score:2>(golang的排序分更高了),其过程大致如下:

  1. 通过zset底层的hash,查找golang目前对应的socre = 1.5
  2. 在跳跃列表中,经过查找过程,找到socre = 1.5所在的kv,并要将其改成score = 2
    • 查看当前socre = 1.5的前后kv,如果score = 2未影响其排序,则直接将当前kv的score改成2即可
    • 如果socre = 2影响了整体排序,则:
      • 删除score = 1.5kv
      • 插入新的socre = 2kv

数据结构跳跃列表的使用

  1. 排序集合zset结构中,使用跳跃列表根据socre排序,存储各集合元素
    • 同时,zset使用hash记录了valuescore的映射
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值