数据结构 -- 跳表

ops/2024/10/18 7:46:23/

文章目录

      • 概要
      • 跳表的结构
      • 跳表的查找过程
      • 插入操作
      • 删除操作
      • 补充

概要

跳表(Skip List)是一种基于链表数据结构,通过增加多级索引来加速查找、插入和删除操作。它可以看作是链表与二分查找的结合体,能够在保持数据有序的同时,实现快速的查找,时间复杂度与平衡树(如红黑树)相同,但实现上更为简单。(跳表又称为:多层级的有序链表

跳表结构:
b站看视频截的图一张图

跳表的结构

跳表通过构建多层级的链表来提高查找效率。最底层的链表是一个完全有序的链表,包含所有的元素。随着层级升高,每一层链表都会跳过一些元素,从而使查找路径变短。通过这种分层的方式,可以在保持数据有序的同时,实现类似于平衡树的快速查找性能。

  • 最底层链表:包含所有元素,按升序排列。所有的搜索最终都会回到这一层,保证能够找到元素。
  • 上层索引:每一层的节点是下一层节点的一个子集,用于跳跃式查找。每层链表都按一定概率选取前一层的节点,形成多个层级。

跳表的典型结构如下图所示:

第3层 :   [3]------------------->[7]----------->[12]
第2层 :   [3]----------->[5]---->[7]----->[10]->[12]
第1层 :   [3]->[4]->[5]->[6]->[7]->[8]->[9]->[10]->[12]
  • 最底层 Level 1 包含所有元素。
  • 上层的每一层是下一层的子集,用于跳跃式查找,加快定位。(降低了查找时间复杂度,但是重复节点需要额外空间

跳表的查找过程

跳表的查找类似于二分查找的思想,通过从上到下、从左到右逐步缩小范围,找到目标元素。

查找步骤:

  1. 从最高层(第一个非空层级)的头节点开始,向右移动,直到当前节点的右边节点大于目标值或右边没有节点。
  2. 如果右边节点大于目标值或者没有右节点,下降到下一层,继续从当前节点向右查找。
  3. 重复步骤 1 和 2,直到降到最底层。
  4. 在最底层找到目标元素,返回结果;如果不存在则返回 null

例如,查找值 9 的过程:

  • 从 第3层 开始,3 -> 7 之后,右边的 129 大,往下到 Level 2。
  • 在 第2层,7 -> 10,右边的 109 大,继续往下到 Level 1。
  • 在 第1层,从 7 -> 8 -> 9,找到了目标元素 9

插入操作

插入操作同样从最上层开始,但每当插入一个新节点时,还需要决定是否将该节点插入到更高层级中(即是否创建该节点的索引)。跳表通过随机化策略来决定节点是否在更高层级出现。

插入步骤:

  1. 按照查找操作,从最高层开始找到插入位置,在最底层找到插入点。
  2. 插入元素到最底层的链表中。
  3. 通过随机选择决定是否将节点插入到更高层级,如果是,则在更高层中插入相应的节点索引。
  4. 重复步骤 3,直到随机选择决定不再向上插入或达到跳表的最高层。

例如,插入 11 的过程:

  • 在 Level 1 找到 1012 之间的位置,插入 11
  • 随机选择决定 11 也出现在 Level 2 中,于是在 Level 2 的 1012 之间插入 11
  • 再次随机决定 11 不会出现在更高层级,插入结束。

删除操作

删除操作与查找操作类似,从最高层开始查找需要删除的元素,找到元素后,在每一层级的链表中删除该元素的索引。

删除步骤:

  1. 从最高层开始,逐步向下查找目标元素。
  2. 一旦找到目标元素,在所有包含该元素的层级中删除该元素的节点。
  3. 当删除完所有层级中的节点后,跳表结构自动调整。

补充

Redis 的有序集合(Sorted Set)就是用跳表实现的,它能够高效支持插入、删除、查找、范围查询等操作。


红黑树:平衡二叉搜索树
B+树:多路平衡搜索树(和跳表类似,所有数据在最后一个层级有序)


面试题:Redis 的有序集合为什么不使用红黑树?
答:跳表范围查询高效

面试题:Redis 的有序集合为什么不使用B+树?
答:

  1. 复杂度和性能:B+ 树的时间复杂度是 O(log n),但是其底层结构需要维护多个层次的节点分裂、合并等复杂操作,特别是在插入和删除时,涉及平衡和重构,带来较高的性能成本。而 跳表(SkipList) 的时间复杂度同样是 O(log n),但其结构更简单,动态操作(如插入、删除、更新)的实现也更加直接,符合 Redis 追求简洁高效的设计理念。

  2. 基于内存的设计:Redis 是一个基于内存的数据库,不需要频繁访问磁盘,因此无需像 B+ 树那样专门为磁盘 I/O 优化。在内存环境下,跳表能够提供足够的性能,且其实现简单,内存占用也较为合理。


❤觉得有用的可以留个关注ya❤


http://www.ppmy.cn/ops/124295.html

相关文章

探索CI/CD:持续集成与持续部署的基本概念

在现代软件开发中,持续集成(CI)和持续部署(CD)已经成为提高开发效率和产品质量的关键实践。本文将详细介绍CI/CD的基本概念、优势以及如何在实际项目中实施CI/CD。 一、什么是持续集成(CI)&…

ECMAScript与JavaScript的区别:深入解析与代码示例

目录 引言 ECMAScript与JavaScript的定义 ECMAScript JavaScript ECMAScript与JavaScript的关系 区别详解 定义上的区别 功能上的区别 实现上的区别 代码示例 ECMAScript 6 (ES6) 特性示例 箭头函数 模板字面量 JavaScript 特有的扩展 在Web开发中的应用 ECMAS…

【Unity基础】Unity用脚本实现内购(IAP)

本文介绍了如何使用脚本实现内购功能。 先看下脚本,代码中根据执行过程添加了序号。 using UnityEngine; using UnityEngine.Purchasing; using UnityEngine.UI;namespace Samples.Purchasing.Core.BuyingConsumables {public class BuyingConsumables : MonoBeha…

【Android】限制TextView大小并允许滑动

关于TextView大小限制 TextView本身支持大小限制,但只支持固定值 这里改用屏幕比例来判断,按照屏幕剩余空间的一定比例来现在TextView最大尺寸 TextView滑动 当TextView空间不足时,需要通过滑动来查看剩余文本 TextView默认是禁用滑动特…

QTday4

数据库头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QSqlDatabase> //数据库管理类 #include<QSqlQuery> //数据库查询类 #include<QSqlRecord> //记录类QT_BEGIN_NA…

使用aloam跑hesai Pandar-XT32激光雷达数据

参考自利用aloam跑数据集_aloam数据集-CSDN博客 第一步&#xff1a;查看bag的信息 输入rosbag info来查看bag包的信息&#xff1a; joeyjoey-Legion-Y7000P-IRX9:~$ rosbag info /home/joey/Downloads/data2022/indoor/LiDAR_IMU.bag path: /home/joey/Downloads/da…

【aws】从s3里拉取驱动 需要后台创建凭证

简答&#xff1a;建一个有s3readonlyaccess的role&#xff0c;绑定给e2就好了 详细步骤&#xff1a; 1.在控制台搜IAM----左侧导航栏点role/角色----右上角创建角色 2.使用案例里选EC2 3.搜s3readonlyaccess这个策略----创建角色 4.选中指定实例&#xff0c;设置&#xff0c;绑…

项目——超级马里奥——Day(2)

争取今天晚上能搞一半啊&#xff0c;啊啊啊啊&#xff0c;感觉事多的忙不过来 设计思路&#xff1a; 1&#xff09;创建并完成常量类 ------->一张图片的情况 先完成对图片的封装------>把图片加载一遍 &#xff08;老实说&#xff0c;我也不太知道为什么&#xff0…