跳表学习笔记,简单分析和引申

在这里插入图片描述

当我们要去查询一个单链表的时候,如果要找某个节点,那么需要遍历整个链表。时间复杂度是 O ( n ) O(n) O(n)。鱼是我们可以优化链表的数据结构,不去一个个的遍历。而是加上索引去遍历索引。

在这里插入图片描述

如果要更加快的搜索想找的节点,可以加第二级索引。

在这里插入图片描述

当元素很多时,为了优化查询效率我们可以设置很多级索引,在Redis中跳表的实现中,将多级索引称为层数。Redis中默认的最大层数为32层,当有 2 64 2^{64} 264个元素时才会达到32层。而单纯看查找最有效率的跳表其实就是可以实现二分查找的有序链表(说单纯看查找效率是因为如果考虑插入的时间复杂度,那么二分的方法进行索引设置就不那么快了)。

空间复杂度为 O ( n ) O(n) O(n)

查询

因为索引有 O ( l o g 2 n ) O(log_2n) O(log2n)层,所以很明显跳表的查询时间复杂度为 O ( l o g 2 n ) O(log_2n) O(log2n)

插入

在这里插入图片描述

当插入一个结点时,我们还需要维护索引,如果我们全部重建索引,那么每次插入都会使时间复杂度为 O ( n ) O(n) O(n)。Redis中采取的方法是,不去均匀的构建索引分布,而是在插入每个结点的同时,随机给这个结点赋予层数的属性,即它具有多少级索引。每个结点在插入时都有1/2概率为一级索引,1/4概率为二级索引以此类推。

随机选 n/2 个元素做为一级索引、随机选 n/4 个元素做为二级索引、随机选 n/8 个元素做为三级索引,依次类推,一直到最顶层索引。

在这里插入图片描述

每个索引都有1/2升级为下一级索引。

// 该 randomLevel 方法会随机生成 1~MAX_LEVEL 之间的数,且 :
//        1/2 的概率返回 1
//        1/4 的概率返回 2
//        1/8 的概率返回 3 以此类推
private int randomLevel() {
  int level = 1;
  float SKIPLIST_P = 0.5;
  // 当 level < MAX_LEVEL,且随机数小于设定的晋升概率时,level + 1
  while (Math.random() < SKIPLIST_P && level < MAX_LEVEL)
    level += 1;
  return level;
}

这样插入的时间复杂度是每个层都插入索引的情况为 O ( l o g n ) O(logn) O(logn)

删除

跳表删除结点,需要把索引也删除。因此很明显删除的时间复杂度为 O ( l o g n ) ( 找 到 结 点 ) + O ( l o g n ) ( 一 共 l o g n 个 索 引 ) = 2 O ( l o g n ) O(logn)(找到结点)+O(logn)(一共logn 个索引)=2O(logn) O(logn)+O(logn)logn=2O(logn)。忽略

Redis使用跳表而不使用红黑树进行查询的原因

  1. 快表原理和实现都比红黑树直观和简单

  2. 在查询,删除,插入和有序输出所有元素上,红黑树和跳表的时间复杂度一样,但是跳表可以更好支持按照范围查找元素。

总结

  1. 跳表是实现二分查找的链表。

  2. 插入结点时跳表会随机赋予level(层数)。

  3. 最底层包含所有结点。

  4. level(x)包含所有level(x+1)的结点。

  5. Redis每层指向每层的下一个结点。

  6. 跳表的插入,查询,删除的时间复杂度与平衡二叉树相近。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值