数据结构——跳表Skip List

本文对跳表的定义、实现、应用等进行简单总结。

一、 介绍

1.定义
跳表(Skip List):是一种概率性数据结构,由William Pugh在1990年提出,主要用于在有序的元素集合上进行快速的搜索、插入和删除操作。跳表的效率与平衡树相当,但实现起来更简单,它通过维护多层链表来提高查找效率。
2. 实现原理
在原有的有序链表上面增加了多级索引,通过索引进行二分查找从而实现高效率查找,其每种操作(搜索、插入、删除)的平均复杂性均为O(logn)
3.特点

特点描述
结构多层链表,每层是下层的子集。
查找效率平均和最坏情况的时间复杂度均为 (O(\log n)),通过多层结构实现快速跳转。
插入效率平均和最坏情况的时间复杂度也是 (O(\log n)),每个新元素通过随机机制决定其存在哪些层中。
删除效率平均和最坏情况的时间复杂度为 (O(\log n)),通过定位到元素并在其存在的每层中删除。
空间复杂度由于节点在多个层级中重复,空间复杂度较单一链表高。
实现简便相较于平衡树和散列表,跳表的实现更直接,调整结构更简单。
用途适用于需要大量动态插入和删除的有序数据集,如数据库和索引系统。

二、跳表的基本结构

  1. 跳表是一组排序的链表,它们分层堆叠在一起,每个层级都包含了部分或全部元素,但每个上层都是下层的一个稀疏子集。
  • 底层(Level 0):包含所有元素的完整链表
  • 上层:每一层都是下一层的稀疏子集,包含的元素逐层减少,每个元素向上晋级的概率通常是固定的(例如1/2)
  • 节点:不仅包含数据,还包含指针:指向同层下一个节点、上层或下层的指针。
  • 示例:
    在这里插入图片描述

2. 跳表的基本操作
(1)查找操作
查找从最顶层开始,如果当前层的下一个节点值大于查找值,就下降到下一层继续查找,直到最底层。如果找到目标值,则查找成功;否则,查找失败。
(2)插入操作
插入元素时,先在底层插入该元素,然后通过抛硬币的方式(随机决定)决定是否将该元素提升到上层。这个过程可能会一直持续到顶层。
(3)删除操作
删除元素先找到该元素(如上所述的查找方式),然后从最底层向上逐层删除该元素。

三、跳表的应用

1. 数据库索引

  • 快速查找:跳表提供了快速的查找性能,适合用作数据库中的索引结构,特别是在需要频繁插入和删除操作的数据库表中。
  • 范围查询:跳表可以有效地支持范围查询,这使得它非常适合在需要进行范围搜索的数据库索引中使用。

2. 缓存系统

  • 有序缓存:在缓存系统中,跳表可以用来保持缓存条目的有序性,便于实现如LRU(最近最少使用)等缓存淘汰算法。

3. 内存管理

  • 动态内存分配:跳表可以用于动态内存分配器中,以追踪空闲内存块的大小和位置,快速分配和释放内存。

4. 并发编程

  • 锁机制:跳表的结构使其更容易被分割成多个独立的部分,这样可以减少锁的竞争,适合并发环境。

5. 时间序列数据

  • 股票和金融数据:跳表适合存储和查询时间序列数据,如股票价格和交易量,支持高效的插入和查询操作。

6. 网络路由

  • 路由表:跳表可以用于网络路由表的实现,快速匹配IP地址和对应的路由。

7. 实时消息系统

  • 消息排序和检索:在需要实时处理和检索大量有序消息的系统中,跳表提供了一个高效的解决方案。

8. 多级索引

  • 文件系统索引:文件系统可以使用跳表来组织文件的元数据,特别是在需要频繁修改文件系统结构时。

四、Java实现跳表

1. 节点类定义

class SkipListNode<T> {T value;SkipListNode<T>[] forward; // 数组用来存储不同层的下一个节点public SkipListNode(int level, T value) {this.value = value;// 注意:数组索引从 0 开始,但是层级从 1 开始计数this.forward = new SkipListNode[level + 1];}
}

2. 跳表类定义

import java.util.Random;class SkipList<T extends Comparable<? super T>> {private SkipListNode<T> head;private int maxLevel;private int level;private Random random;public SkipList() {// 最大层数设置为 16,实际应用中可以根据数据规模调整maxLevel = 16;level = 0;// 头节点的层级最大,所有层都有head = new SkipListNode<>(maxLevel, null);random = new Random();}// 生成随机层级private int randomLevel() {int lvl = 1;while (random.nextInt() % 2 == 0 && lvl < maxLevel) {lvl++;}return lvl;}// 查找方法public boolean search(T target) {SkipListNode<T> current = head;for (int i = level; i >= 0; i--) {while (current.forward[i] != null && current.forward[i].value.compareTo(target) < 0) {current = current.forward[i];}}current = current.forward[0];return current != null && current.value.compareTo(target) == 0;}// 插入方法public void insert(T value) {SkipListNode<T>[] update = new SkipListNode[maxLevel + 1];SkipListNode<T> current = head;for (int i = level; i >= 0; i--) {while (current.forward[i] != null && current.forward[i].value.compareTo(value) < 0) {current = current.forward[i];}update[i] = current;}current = current.forward[0];if (current == null || !current.value.equals(value)) {int lvl = randomLevel();if (lvl > level) {for (int i = level + 1; i <= lvl; i++) {update[i] = head;}level = lvl;}SkipListNode<T> newNode = new SkipListNode<>(lvl, value);for (int i = 0; i <= lvl; i++) {newNode.forward[i] = update[i].forward[i];update[i].forward[i] = newNode;}}}// 删除方法public void delete(T value) {SkipListNode<T>[] update = new SkipListNode[maxLevel + 1];SkipListNode<T> current = head;for (int i = level; i >= 0; i--) {while (current.forward[i] != null && current.forward[i].value.compareTo(value) < 0) {current = current.forward[i];}update[i] = current;}current = current.forward[0];if (current != null && current.value.equals(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--;}}}
}

五、跳表与红黑树、B树、B+树

数据结构平均查找时间复杂度平均插入时间复杂度平均删除时间复杂度空间效率实现复杂度特点与应用场景
跳表(O(\log n))(O(\log n))(O(\log n))较低较低易于实现和理解,适用于需要快速插入和删除的场景,如缓存系统
红黑树(O(\log n))(O(\log n))(O(\log n))较高保持平衡的二叉搜索树,适用于需要保持数据平衡的场景,如操作系统的各类调度
B树(O(\log n))(O(\log n))(O(\log n))广泛用于数据库和文件系统索引,优化磁盘读写效率和减少I/O操作
B+树(O(\log n))(O(\log n))(O(\log n))优化用于数据库和文件系统索引,叶节点互联提高区间查询效率

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/36008.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

英语智汇学习系统

目 录 1 软件概述 1.1 项目研究背景及意义 2 系统相关技术 2.1 HTML、WXSS、JAVASCRIPT技术 2.2 Vanilla框架 2.3 uni-app框架 2.4 MYSQL数据库 3 需求分析 3.1 可行性分析 3.2 功能需求分析 3.3 系统用户及用例分析 3.4 非功能需求分析 3.5 数据流图…

windows USB 设备驱动开发-总章

通用串行总线 (USB) 提供可扩展的即插即用串行接口&#xff0c;确保外围设备的标准、低成本的连接。 USB 设备包括键盘、鼠标、游戏杆、打印机、扫描仪、存储设备、调制解调器、视频会议摄像头等。USB-IF 是一个特别兴趣组 (SIG)&#xff0c;负责维护官方 USB 规范、测试规范和…

如何提高项目风险的处理效率?5个重点

提高项目风险的处理效率&#xff0c;有助于迅速识别和应对风险&#xff0c;减少风险导致的延误&#xff0c;降低成本&#xff0c;提升项目质量&#xff0c;确保项目按时交付。如果项目风险处理效率较低&#xff0c;未能及时发现和处理风险&#xff0c;导致问题累积&#xff0c;…

小米汽车SU7全色系H5自适应展示源码

为了满足广大车迷和潜在消费者对小米汽车SU7全色系的视觉体验需求&#xff0c;我们特别推出了一款基于HTML的自适应H5源码&#xff0c;用于在线展示小米汽车SU7的全色系。这款源码不仅兼容各种设备和屏幕尺寸&#xff0c;而且能够完美地呈现出小米汽车SU7的优雅外观和精致细节。…

【qt】CAD下

目录 一.前言二.缩放1.逻辑2.获取图形项选中的个数3.获取图形项并放大4.视图缩放5.完整代码6.效果展示7.缩小完整代码 三.旋转1.图形项进行旋转2.视图的旋转3.完整代码4.效果展示5.右转代码 四.恢复1.图形项复原2.视图复原3.完整代码4.效果展示 五.前后置1.设置z轴的值2.后置代…

Linux 扩容 根分区

CentOS7&#xff0c;LVM根分区扩容步骤&#xff1a; LVM扩容思维流程&#xff1a;创建一个物理分区–>将这个物理分区转换为物理卷–>把这个物理卷添加到要扩展的卷组中–>然后才能用extend命令扩展此卷组中的逻辑卷 1.查看现有分区大小 df -TH 2.关机增加大小为40G(…

appinventor2中求某个值在列表中的索引用什么方法?

使用“求对象在列表中的位置”方法就可以了&#xff1a; 返回指定对象在列表中的位置&#xff0c;从 1 开始&#xff0c;如果不在列表中&#xff0c;则返回 0。 相应地&#xff0c;知道了索引&#xff0c;从列表中取值得方法是&#xff1a;选择列表中索引值对应的列表项 返回…

linux下安装kkFileView4

kkFileView为文件文档在线预览解决方案&#xff0c;该项目使用流行的spring boot搭建&#xff0c;易上手和部署&#xff0c;基本支持主流办公文档的在线预览&#xff0c;如doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,图片,视频,音频等等 安装kkFileView前需要安装LibreOffic…

昇思MindSpore学习总结二——张量

1、张量 张量tensor表示的是一个多维的矩阵&#xff0c;比如零维就是一个点&#xff0c;一维就是向量&#xff0c;二维就是一般的矩阵&#xff0c;多维就相当于一个多维的数组&#xff0c;这和numpy是对应的&#xff0c;而且PyTorch的Tensor和numpy的ndarray可以相互转换&#…

Python | Leetcode Python题解之第200题岛屿数量

题目&#xff1a; 题解&#xff1a; class Solution:def dfs(self, grid, r, c):grid[r][c] 0nr, nc len(grid), len(grid[0])for x, y in [(r - 1, c), (r 1, c), (r, c - 1), (r, c 1)]:if 0 < x < nr and 0 < y < nc and grid[x][y] "1":self.d…

【论文速读】|MEDFUZZ:探索大语言模型在医学问题回答中的鲁棒性

本次分享论文&#xff1a;MEDFUZZ: EXPLORING THE ROBUSTNESS OF LARGE LANGUAGE MODELS IN MEDICAL QUESTION ANSWERING 基本信息 原文作者&#xff1a;Robert Osazuwa Ness, Katie Matton, Hayden Helm, Sheng Zhang, Junaid Bajwa, Carey E. Priebe, Eric Horvitz 作者单…

Lua博客网站支持搜索、评论、登录注册

该简易博客示例用于学习网站的基础知识与MySQL数据库。 简述&#xff1a;开源Lua网站开发服务(FastWeb)支持&#xff1a;注册、登录、文章分页、评论分页、简易权限管理和搜索功能。发帖功能支持Markdown(支持记忆功能)图示&#xff1a;

Java之线程相关应用实现

后台线程 一个进程中只有后台进程运行&#xff0c;该进程将会结束。 新创建的线程默认为前台线程&#xff0c;Java中只要有一个前台线程运行&#xff0c;就不会结束程序&#xff0c;如果只有后台线程运行&#xff0c;程序就会结束&#xff0c;可以在线程对象启动前执行setDae…

【js + ckeditor】插入base64格式的图片

一、需求说明 直接把图片转成base64插入到富文本 二、需求分析 1、富文本图片格式处理位置 在ckeidtor的目录下有个plugins文件夹&#xff0c;在plugins下新建一个文件夹&#xff08;自己命名&#xff0c;如simpleupload&#xff09;&#xff0c;进入simpleupload文件夹&…

微服务和kafka

一、微服务简介 1.单体架构 分布式--微服务--云原生 传统架构&#xff08;单机系统&#xff09;&#xff0c;一个项目一个工程&#xff1a;比如商品、订单、支付、库存、登录、注册等等&#xff0c;统一部署&#xff0c;一个进程 all in one的架构方式&#xff0c;把所有的…

深入探讨C++的高级反射机制(2):写个能用的反射库

在现代软件开发中&#xff0c;反射是一种强大的特性&#xff0c;它可以支持程序在运行时查询和调用对象的属性和方法。 但是在C中&#xff0c;没有内置的反射机制。我们可以通过一些巧妙的技术模拟反射的部分功能。 上一篇文章写了个简单的反射功能&#xff0c;这回完善一下&a…

3.PyQt6常用基本控件

目录 常用控件 1.文本类控件 1.QLable标签控件 1.设置标签文本 2.设置标签文本和对齐方式 3.换行显示 4.添加超链接 5.为标签设置图片 6.获取标签文本 2.QLineEdit单行文本控件 3.QTextEdit多行富文本控件 4.QPlainTextEdit纯文本控件 5.QSpinBox整数数字选择控件 …

开发板以电脑为跳板连接互联网

标题 开发板以电脑为跳板连接互联网网络共享方式桥接方式 开发板以电脑为跳板连接互联网 分享下用网线直连电脑的开发板如何以电脑为跳板连接互联网的两个方法。 网络共享方式桥接方式 补充下&#xff0c;我的电脑连接的是无线网络&#xff0c;开发板和电脑是用网线进行连接的…

Python 高级编程:文件操作与错误处理

在前几篇文章中&#xff0c;我们介绍了Python的基本语法、函数和模块以及面向对象编程。这些知识对于大部分日常编程问题已经足够&#xff0c;但对于需要分析大数据的人来说&#xff0c;这些还不够。本章将介绍Python的文件操作以及错误处理与调试。 目录 文件操作读文件写文…

C语言单链表的算法之插入节点

一&#xff1a;访问各个节点中的数据 &#xff08;1&#xff09;访问链表中的各个节点的有效数据&#xff0c;这个访问必须注意不能使用p、p1、p2&#xff0c;而只能使用phead &#xff08;2&#xff09;只能用头指针不能用各个节点自己的指针。因为在实际当中我们保存链表的时…