数据结构之:跳表
跳表(Skip List)是一种概率性数据结构,它通过在普通有序链表的基础上增加多级索引层来实现快速的查找、插入和删除操作。跳表的效率可以与平衡树相媲美,其操作的时间复杂度也是O(log n),但跳表的结构更简单,更易于实现。
跳表的核心特征
- 多层结构:跳表包含多个层级。最底层(第0层)包含所有的元素。每一层都是下一层的“快速通道”,每个元素出现在上层的概率通常是1/2。
- 头节点:跳表有一个头节点(head),它在所有层级中都存在。头节点的值通常不存储实际的数据,它的目的是为了搜索、插入和删除操作提供一个统一的起点。
- 随机层级:每个新插入的节点的层数是通过随机过程决定的,以确保跳表的平衡性。这意味着高层索引不会过于密集或稀疏。
数据结构组件
- 节点(SkipListNode):每个节点包含的信息有:
- 值(value):存储的数据值。
- 前进指针(forward):一个指针数组,指向同一层级的下一个节点以及上层对应的节点。
- 头节点(Head):是一个特殊的节点,它的
forward
指针数组的长度等于跳表的最大层数。它在所有层级上都指向该层的第一个实际节点(如果存在)。 - 层数(Level):跳表当前的最大层数。这个值是动态的,随着新节点的插入可以增加。
操作原理
- 搜索(Search):从头节点开始,在最高层级搜索,如果当前节点的下一个节点的值小于目标值,则向前移动;如果大于目标值,则下降到下一层级继续搜索,直至找到目标值或搜索失败。
- 插入(Insert):首先通过随机过程确定新节点的层数。然后从最高层开始寻找插入位置,逐层向下直到达到新节点应存在的最低层级。在每一层,将新节点插入到适当的位置,并更新相关节点的指针。
- 删除(Delete):与搜索类似,首先定位要删除的节点。然后从其所在的最高层开始,逐层向下删除节点,并更新指针。
优点与应用
- 简单性:跳表的数据结构和算法相对简单,特别是与平衡树和B树等结构相比。
- 动态性:跳表可以很容易地支持动态数据集合的操作,如实时插入和删除。
- 效率:对于大多数操作,跳表可以提供对数时间复杂度的性能,适用于需要快速搜索操作的场景,如数据库索引和内存数据库。
跳表通过简单的随机化过程来避免复杂的重平衡操作,使得它成为一种既高效又易于实现的数据结构选项。
简单的跳表实现示例
import java.util.Random;class SkipListNode {int value;SkipListNode[] forward; // 指向不同层的指针数组public SkipListNode(int value, int level) {this.value = value;this.forward = new SkipListNode[level + 1];}
}public class SkipList {private static final float P = 0.5f;private static final int MAX_LEVEL = 16;private SkipListNode head;private int level;private Random random;public SkipList() {level = 0;head = new SkipListNode(0, MAX_LEVEL);random = new Random();}// 随机生成节点的层数private int randomLevel() {int lvl = 1;while (random.nextFloat() < P && lvl < MAX_LEVEL) {lvl++;}return lvl;}// 插入节点public void insert(int value) {int lvl = randomLevel();SkipListNode newNode = new SkipListNode(value, lvl);SkipListNode current = head;SkipListNode[] update = new SkipListNode[MAX_LEVEL + 1];for (int i = level; i >= 0; i--) {while (current.forward[i] != null && current.forward[i].value < value) {current = current.forward[i];}update[i] = current;}for (int i = 0; i <= lvl; i++) {newNode.forward[i] = update[i].forward[i];update[i].forward[i] = newNode;}if (lvl > level) {level = lvl;}}// 查找节点public boolean search(int value) {SkipListNode current = head;for (int i = level; i >= 0; i--) {while (current.forward[i] != null && current.forward[i].value < value) {current = current.forward[i];}}current = current.forward[0];return current != null && current.value == value;}// 删除节点public void delete(int value) {SkipListNode[] update = new SkipListNode[MAX_LEVEL + 1];SkipListNode current = head;for (int i = level; i >= 0; i--) {while (current.forward[i] != null && current.forward[i].value < value) {current = current.forward[i];}update[i] = current;}current = current.forward[0];if (current.value == value) {for (int i = 0; i <= level; i++) {if (update[i].forward[i] != current) break;update[i].forward[i] = current.forward[i];}while (level > 0 && head.forward[level] == null) {level--;}}}// 打印跳表的内容public void display() {System.out.println("SkipList: ");for (int i = 0; i <= level; i++) {SkipListNode node = head.forward[i];System.out.print("Level " + i + ": ");while (node != null) {System.out.print(node.value + " ");node = node.forward[i];}System.out.println();}}
}// 使用示例
public class Main {public static void main(String[] args) {SkipList list = new SkipList();list.insert(3);list.insert(6);list.insert(7);list.insert(9);list.insert(12);list.insert(19);list.insert(17);list.display();System.out.println("Searching 6: " + list.search(6));System.out.println("Searching 15: " + list.search(15));list.delete(6);System.out.println("After deleting 6: ");list.display();}
}
这段代码首先定义了SkipListNode
类,它是跳表节点的结构,包括节点值和一个数组forward
,数组中每个元素是对应层级的下一个节点的引用。SkipList
类实现了跳表,包括初始化、插入、查找、删除和打印跳表的方法。
insert
方法用于插入新的节点。search
方法用于查找一个值,如果找到,则返回true
。delete
方法用于删除一个值。display
方法用于打印跳表的所有层级和节点。
通过一个具体的例子来说明跳表的插入过程
假设我们有一个跳表,它当前的状态如下,其中每一行代表一个层级(层级0是最底层,包含所有元素):
层级3:1 --------------------------------> 9
层级2:1 ------------> 5 ------------> 9
层级1:1 ----> 3 ----> 5 ----> 7 ----> 9
层级0:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 9
现在,我们想要插入一个新的节点,值为8
,并假设通过随机过程,决定新节点8
将出现在层级0、1和2上(不出现在层级3上)。下面是插入过程的步骤:
步骤1:寻找每一层的插入位置
从跳表的最高层(在这个例子中是层级3)开始寻找,直到找到比插入值小的最大节点。因为8
不会被插入到层级3,我们直接从层级2开始:
- 层级2:从
1
开始,遍历到5
,因为9
大于8
,所以5
是层级2的插入位置。 - 层级1:同样从
1
开始,遍历到5
,然后到7
,因为9
大于8
,所以7
是层级1的插入位置。 - 层级0:从
1
开始,按顺序遍历,直到7
,因为9
大于8
,所以7
是层级0的插入位置。
步骤2:插入节点并更新指针
- 层级2:在
5
和9
之间插入8
,更新5
的下一个指针为8
,8
的下一个指针为9
。 - 层级1:在
7
和9
之间插入8
,更新7
的下一个指针为8
,8
的下一个指针为9
。 - 层级0:在
7
和9
之间插入8
,更新7
的下一个指针为8
,8
的下一个指针为9
。
插入8
后,跳表变为:
层级3:1 --------------------------------> 9
层级2:1 ------------> 5 -------> 8 ----> 9
层级1:1 ----> 3 ----> 5 ----> 7 -> 8 -> 9
层级0:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
步骤3:调整跳表的总层数(如果需要)
在这个例子中,新插入的节点8
并没有增加跳表的总层数,因此不需要调整。
通过这个例子,你可以看到插入过程如何在每一层找到正确的插入位置,并更新指针来维护跳表的结构。这个过程确保了跳表的搜索效率,使得搜索、插入和删除操作的时间复杂度都为O(log n)。
相关文章:
数据结构之:跳表
跳表(Skip List)是一种概率性数据结构,它通过在普通有序链表的基础上增加多级索引层来实现快速的查找、插入和删除操作。跳表的效率可以与平衡树相媲美,其操作的时间复杂度也是O(log n),但跳表的结构更简单,…...
matlab 线性四分之一车体模型
1、内容简介 略 57-可以交流、咨询、答疑 路面采用公式积分来获得,计算了车体位移、非悬架位移、动载荷等参数 2、内容说明 略 3、仿真分析 略 线性四分之一车体模型_哔哩哔哩_bilibili 4、参考论文 略...
LeetCode第二题: 两数相加
文章目录 题目描述示例 解题思路 - 迭代法Go语言实现 - 迭代法算法分析 解题思路 - 模拟法Go语言实现 - 模拟法算法分析 解题思路 - 优化模拟法主要方法其他方法的考虑 题目描述 给出两个非空的链表用来表示两个非负的整数。其中,它们各自的位数是按照逆序的方…...
web组态插件
插件演示地址:http://www.byzt.net 关于组态软件,首先要从组态的概念开始说起。 什么是组态 组态(Configure)的概念来自于20世纪70年代中期出现的第一代集散控制系统(Distributed Control System)…...
Android14 InputManager-InputManagerService环境的构造
IMS分为Java层与Native层两个部分,其启动过程是从Java部分的初始化开始,进而完成Native部分的初始化。 □创建新的IMS对象。 □调用IMS对象的start()函数完成启动 同其他系统服务一样,IMS在SystemServer中的ServerT…...
搜维尔科技:【周刊】适用于虚拟现实VR中的OptiTrack
适用于 VR 的 OptiTrack 我们通过优化对虚拟现实跟踪最重要的性能指标,打造世界上最准确、最易于使用的广域 VR 跟踪器。其结果是为任何头戴式显示器 (HMD) 或洞穴自动沉浸式环境提供超低延迟、极其流畅的跟踪。 OptiTrack 主动式 OptiTrack 世界领先的跟踪精度和…...
matlab倒立摆小车LQR控制动画
1、内容简介 略 54-可以交流、咨询、答疑 2、内容说明 略 摆杆长度为 L,质量为 m 的单级倒立摆(摆杆的质心在杆的中心处),小车的质量为 M。在水平方向施加控制力 u,相对参考系产生位移为 y。为了简化问题并且保其实质不变,忽…...
【C++】类和对象(2)
目录 1. 初始化列表 2.explicit关键字 3. Static成员 3. 友元 3.1友元函数 3.2友元类 4. 内部类 5.匿名对象 1. 初始化列表 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值,但是这个过程并不能称为对对…...
用Python实现创建十二星座数据分析图表
下面小编提供的代码中,您已经将pie.render()注释掉,并使用了pie.render_to_file(十二星座.svg)来将饼状图渲染到一个名为十二星座.svg的文件中。这是一个正确的做法,如果您想在文件中保存图表而不是在浏览器中显示它。 成功创建图表…...
备战蓝桥杯————递归反转单链表的一部分
递归反转单链表已经明白了,递归反转单链表的一部分你知道怎么做吗? 一、反转链表Ⅱ 题目描述 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left < right 。请你反转从位置 left 到位置 right 的链表节点,返回 反…...
rabbitmq知识梳理
一.WorkQueues模型 Work queues,任务模型。简单来说就是让多个消费者绑定到一个队列,共同消费队列中的消息。 当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,…...
【数据结构与算法】动态规划法解题20240227
动态规划法 一、什么是动态规划二、动态规划的解题步骤三、509. 斐波那契数1、动规五部曲: 四、70. 爬楼梯1、动规五部曲: 五、746. 使用最小花费爬楼梯1、动规五部曲: 一、什么是动态规划 动态规划,英文:Dynamic Pro…...
备战蓝桥杯—— 双指针技巧巧答链表2
对于单链表相关的问题,双指针技巧是一种非常广泛且有效的解决方法。以下是一些常见问题以及使用双指针技巧解决: 合并两个有序链表: 使用两个指针分别指向两个链表的头部,逐一比较节点的值,将较小的节点链接到结果链表…...
半监督节点分类-graph learning
半监督节点分类相当于在一个图当中,用一部分节点的类别上已知的,有另外一部分节点的类别是未知的,目标是使用有标签的节点来推断没有标签的节点 注意 半监督节点分类属于直推式学习,直推式学习相当于出现新节点后,需要…...
软件文档-运维-开发-管理-资质-评审-招投标-验收
开发文档:这类文档主要用于记录软件的开发过程和细节,包括: 《功能要求》:描述了软件应具备的功能,是软件开发的基础。《投标方案》:向潜在的客户或招标方展示公司的技术和项目实施能力。《需求分析》&…...
猫头虎分享已解决Bug || Vue中的TypeError: Cannot read property ‘name‘ of undefined 错误
博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通鸿蒙》 …...
技术应用:使用Spring Boot、MyBatis Plus和Dynamic DataSource实现多数据源
引言 在现代的软件开发中,许多应用程序需要同时访问多个数据库。例如,一个电子商务平台可能需要访问多个数据库来存储用户信息、产品信息和订单信息等。在这种情况下,使用多数据源是一种常见的解决方案,它允许我们在一个应用程序…...
C# Onnx 使用onnxruntime部署实时视频帧插值
目录 介绍 效果 模型信息 项目 代码 下载 C# Onnx 使用onnxruntime部署实时视频帧插值 介绍 github地址:https://github.com/google-research/frame-interpolation FILM: Frame Interpolation for Large Motion, In ECCV 2022. The official Tensorflow 2…...
编程笔记 Golang基础 016 数据类型:数字类型
编程笔记 Golang基础 016 数据类型:数字类型 1. 整数类型(Integer Types)a) 固定长度整数:b) 变长整数: 2. 浮点数类型(Floating-Point Types)3. 复数类型(Complex Number Types&…...
一周学会Django5 Python Web开发-会话管理(CookiesSession)
锋哥原创的Python Web开发 Django5视频教程: 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计26条视频,包括:2024版 Django5 Python we…...
QT之QString.arg输出固定位数
问题描述 我需要用QString输出一个固定位数的数字字符串。起初我的代码是这样: int img_num 1 auto new_name QString("%1.png").arg((int)img_num, 3, 10, 0); //最后一个参数用u0也是一样的 qDebug() << "new_name:" << new…...
Linux下各种压缩包的压缩与解压
tar 归档,不压缩,常见后缀 .tar # 将文件夹归档成为一个包 tar cf rootfs.tar rootfs # 将归档包还原为文件夹 tar xf rootfs.tar # 将归档包还原到路径 a/b/c tar xf rootfs.tar -C a/b/cgzip压缩, 常见后缀 .tar.gz .tgz # 压缩 tar czf …...
【ctfshow—web】——信息搜集篇1(web1~20详解)
ctfshow—web题解 web1web2web3web4web5web6web7web8web9web10web11web12web13web14web15web16web17web18web19web20 web1 题目提示 开发注释未及时删除 那就找开发注释咯,可以用F12来查看,也可以CtrlU直接查看源代码呢 就拿到flag了 web2 题目提示 j…...
GEE入门篇|遥感专业术语(实践操作4):光谱分辨率(Spectral Resolution)
目录 光谱分辨率(Spectral Resolution) 1.MODIS 2.EO-1 光谱分辨率(Spectral Resolution) 光谱分辨率是指传感器进行测量的光谱带的数量和宽度。 您可以将光谱带的宽度视为每个波段的波长间隔,在多个波段测量辐射亮…...
c++中模板的注意事项
1. 模板定义时,<>中的虚拟类型参数不能为空。(因为我们使用模板就是希望使用模拟类型代替其它的类型,如果我们不定义就没有意义了) 2. 无论是定义函数模板还是类模板,其实template定义与后面使用虚拟类型的类或者函数,是…...
【代码随想录python笔记整理】第十三课 · 链表的基础操作 1
前言:本笔记仅仅只是对内容的整理和自行消化,并不是完整内容,如有侵权,联系立删。 一、链表 在之前的学习中,我们接触到了字符串和数组(列表)这两种结构,它们具有着以下的共同点:1、元素按照一定的顺序来排列。2、可以通过索引来访问数组中的元素和字符串中的字符。由此,…...
JAVA工程师面试专题-《Mysql》篇
目录 一、基础 1、mysql可以使用多少列创建索引? 2、mysql常用的存储引擎有哪些 3、MySQL 存储引擎,两者区别 4、mysql默认的隔离级别 5、数据库三范式 6、drop、delete 与 truncate 区别? 7、IN与EXISTS的区别 二、索引 1、索引及索…...
@ 代码随想录算法训练营第4周(C语言)|Day22(二叉树)
代码随想录算法训练营第4周(C语言)|Day22(二叉树) Day22、二叉树(包含题目 ● 235. 二叉搜索树的最近公共祖先 ● 701.二叉搜索树中的插入操作 ● 450.删除二叉搜索树中的节点 ) 235. 二叉搜索树的最近公…...
福特锐界2021plus 汽车保养手册
福特锐界2021plus汽车保养手册两页,零部件保养要求,电子版放这里方便查询:...
c++进阶路线
学完C后的进阶路线-初学者勿入【程序员Rock】_哔哩哔哩_bilibili 1.系统训练代码阅读能力 代码阅读工具: 1).Source Insight(阅读大型源码) 2).understand(整体代码模块关系构建) 3).SOURCETRAIL 代码阅读能力--千行级 嵌入…...
wordpress幻灯片尺寸/淮北网络推广
点击上方蓝色字体,选择“设为星标”回复"面试"获取更多惊喜大数据面试提升私教训练营上线Hi,我是王知无,一个大数据领域的原创作者。 放心关注我,获取更多行业的一手消息。摘要:实时数仓以提供低延时数据指标…...
抖音小程序开发公司/深圳seo优化外包公司
Spring2.5 的事物配置:<!-- 配置事务通知 --><tx:advice id"txAdvice" transactionManagertxManager><!-- REQUIRED:表示当前方法必须运行在一个事物中,没有事物则创建一个。SUPPORTS:表示当前方法不需要事物-->…...
临沂教育平台网站建设/网页seo搜索引擎优化
文章目录前言一、二叉树的遍历1.1 创建二叉树1.2 二叉树的遍历方式1.3 二叉树遍历的实现二、二叉树的其他操作前言 如果你还不知道树及二叉树的概念,请先看这篇文章树和二叉树的介绍 对于二叉树,我们学习的重点是二叉树的结构,而想要学好二…...
招工做哪个网站/百度大数据预测平台
深入C系列: 1、《C STL中文版》 2、《More Effective C(中文版)》 3、《深度探索C对象模型》 4、《泛型编程与STL》 5、《Effective STL》 6、《C Primer中文版》 7、《C程序设计原理与实践》 8、《C编程思想》 9、《C编程规范&…...
网站 建设ppt模板/关键词搜索排名工具
最近的工作我在做一个有关于消息发送和接受封装工作。大概流程是这样的,消息中间件是采用rabbitmq,为了保证消息的绝对无丢失,我们需要在发送和接受前对消息进行DB落地。在发送前我会先进行DB的插入,单表插入,所以在性…...
wordpress flash加载插件/百度刷自己网站的关键词
最近跟我的一些读者交流,有一位读者的经历让我记忆深刻:“有一次和大学同学聚会,和几个在BAT的同学聊了聊技术,发现自己在创业公司这几年,完全是吃老本的状态,没有什么机会精进技术,同样是工作了…...