数据结构-05-跳表SkipList

1-什么是跳表

       跳表SkipList是一种随机化的数据结构,基于并联的链表,实现简单,插入、删除、查找的复杂度均为 O(logN)(大多数情况下,因为是实现上是概率问题),因为其性能匹敌红黑树且实现较为简单,因此在很多著名项目都用 SkipList 来代替红黑树,例如Redis中的有序集合zset 的底层存储结构就是用的skiplist。
        跳跃列表由 William Pugh 发明。他在 Communications of the ACM发表了《Skip lists: a probabilistic alternative to balanced trees》,在其中详细描述了他的工作。

假设原始链表的数据如下:链表中存储的数据是有序的。

       我们知道这种链表结构查询数据的时间复杂度是O(n)。但是如果我们对链表建立"索引",把节点数据提取出来放在上一级(索引层),这样是不是就可以提高查询效率了呢?比如我们查找元素83;如果按照原始链表,要查询8个节点,采用下面这个结构,只需要查询5个节点。如果数据量越大,优势就更加明显。

这种链表加多级索引的结构,就是跳表。

2-跳表的查询

        我们知道,在一个单链表中查询某个数据的时间复杂度是O(n)。那么跳表的时间复杂度是多少呢?
      假设每两个结点会抽出一个结点作为上一级索引的结点,那第一级索引的结点个数大约就是n/2,第二级索引的结点个数大约就是n/4,第三级索引的结点个数大约就是n/8,依次类推,也就是说,第k级索引的结点个数是第k-1级索引的结点个数的1/2,第k索引结点的个数就是n/(2^k)。
       假设最高级索引有两个节点,最高级索引是k,总节点数是n,那么n/(2^k)=2,k=logn -1(以2为底的对数)。如果包含原始链表这一层,整个跳表的高度就是logn。我们在跳表中查询某个数据的时候,如果每一层都要遍历m个结点,那在跳表中查询一个数据的时间复杂度就是O(m*logn)。一般m是常数,所以在跳表中查询任意数据的时间复杂度就是O(logn)。这个时间复杂度是不是跟二分查找一样,很高效了。但是这种效率的提升,是以空间换时间的理念来实现的。

       假设我们每两个节点抽取一个,需要多使用n/2+n/4+n/8…+8+4+2=n-2。跳表的空间复杂度是O(n)。也就是说,如果将包含n个结点的单链表构造成跳表,我们需要额外再用接近n个结点的存储空间。假设我们每3个节点抽取一个,总的索引结点大约就是n/3+n/9+n/27+…+9+3+1=n/2,空间复杂度还是O(n),但比上面的每两个结点抽一个结点的索引构建方法,要减少了一半的索引结点存储空间。

        其实我们不必太在意索引占用的额外空间,因为实际的软件开发中,原始链表中存储的有可能是很大的对象,而索引结点只需要存储关键值和几个指针,并不需要存储对象,所以当对象比索引结点大很多时,那索引占用的额外空间就可以忽略了。

3-跳表的插入-删除-索引的动态更新

       插入:在单链表中,一旦定位好要插入的位置,插入结点的时间复杂度是很低的,就是O(1)。但是,这里为了保证原始链表中数据的有序性,我们需要先找到要插入的位置,这个查找操作就会比较耗时O(n)。但是,对于跳表来说,我们讲过查找某个结点的的时间复杂度是O(logn),所以这里查找某个数据应该插入的位置,方法也是类似的,时间复杂度也是O(logn)

       删除:如果这个结点在索引中也有出现,我们除了要删除原始链表中的结点,还要删除索引中的。因为单链表中的删除操作需要拿到要删除结点的前驱结点,然后通过指针操作完成删除。所以在查找要删除的结点的时候,一定要获取前驱结点。

       索引动态更新:当我们不停地往跳表中插入数据时,如果我们不更新索引,就有可能出现某2个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。作为一种动态数据结构,我们需要某种手段来维护索引与原始链表大小之间的平衡,也就是说,如果链表中结点多了,索引结点就相应地增加一些,避免复杂度退化,以及查找、插入、删除操作性能下降。
       当我们往跳表中插入数据的时候,我们可以选择同时将这个数据插入到部分索引层中。如何选择加入哪些索引层呢?我们通过一个随机函数,来决定将这个结点插入到哪几级索引中,比如随机函数生成了值K,那我们就将这个结点添加到第一级到第K级这K级索引中。随机函数的选择很有讲究,从概率上来讲,能够保证跳表的索引大小和数据大小平衡性,不至于性能过度退化。

4-redis跳表使用

       Redis中的有序集合zset 的底层存储结构就是用的skiplist,为何不使用红黑树等平衡树?主要原因有以下几点:

1-高效的查找操作:跳表通过建立多层索引,可以在有序集合中实现快速的查找操作。相比于传统的平衡树结构(如红黑树),跳表的查找操作具有更低的时间复杂度,平均情况下为O(log n)。
2-简单且易于实现:相对于其他复杂的数据结构(如红黑树或AVL树),跳表的实现相对简单且容易理解。它没有复杂的平衡调整操作,只需通过维护索引层来保持有序性和高效性。
3-空间效率较高:跳表通过层级结构来建立索引,每个节点只需额外存储少量的指针信息。相比于一些平衡树结构,跳表在空间使用上通常更加高效。
       还有一个业务功能原因:对于按照区间查找数据ZRANGE这个操作,跳表可以做到O(logn)的时间复杂度定位区间的起点,然后在原始链表中顺序往后遍历就可以了。这样做非常高效。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

jetpack compose 学习(-)

年底了,无聊的时间总是缓慢的,找个事情做一做,打发打发时间,刚好看到jetpack compose 学习学习,毕竟androidStudio 默认创建的项目都带上了这个,学习网站:https://developer.android.com/jetpack/compose/modifiers?hlzh-cn 1. 首先androidStudio创建一个新项目 喜欢kotlin的,…

面向工业物联网的5G机器学习研究综述

源自:信息与控制 作者:柴浩轩 金曦 许驰 夏长清 摘 要 随着计算机技术不断应用于工业物联网,工业系统中的数据传输愈加需要支持高实时、高可靠、高带宽以及海量连接的特性。传统的网络已经无法满足这些需求,5G网络因其高速率…

ASO优化之如何在应用商城突围

再好的内容没有营销也很难成功。评判一个APP是否在应用市场获得关注的一个重要标准就是下载量。但是,光被人发现你的APP应用是没有用的,还要精确定位有需要的目标群体才能更好的推销出去。在制定合适的优化策略的,一定要对市场行情有一个比较…

C# 图解教程 第5版 —— 第18章 泛型

文章目录 18.1 什么是泛型18.2 C# 中的泛型18.3 泛型类18.3.1 声明泛型类18.3.2 创建构造类型18.3.3 创建变量和实例18.3.4 使用泛型的示例18.3.5 比较泛型和非泛型栈 18.4 类型参数的约束18.4.1 Where 子句18.4.2 约束类型和次序 18.5 泛型方法18.5.1 声明泛型方法18.5.2 调用…

青少年CTF-Misc(持续更新中)

FLAG:当觉得自己很菜的时候,就静下心来学习 专研方向:Web安全,CTF 每日emo:听一千遍反方向的钟,我们能回到过去吗? 1.StegoTXT: 解压缩文件。发现字母中存在覆盖。使用0宽隐写在线解密得到flag…

Slate基础使用说明

目录 Slate基础使用说明 1. 简单教程 2. 要点说明 2.1 TCommands以及TCommands基类 2.2 FUICommandInfo 2.3 FUICommandList 2.4 FUIAction 2.5 UICommand 3. 代码源码 4. 工具使用 4.1 Display Ul Extension Points 4. 参考文章 Slate基础使用说明 1.…

设计模式02创建者模式

创建者模式 参考网课:黑马程序员Java设计模式详解 博客笔记 创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。 这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。 创建型模式分为&#…

下一代Wi-Fi技术:Wi-Fi 7(IEEE 802.11be EHT)

文章目录 Wi-Fi 7名词解释Wi-Fi 7的产生背景Wi-Fi 7的发布时间Wi-Fi 7的技术优势Wi-Fi 7 vs Wi-Fi 6Wi-Fi 7支持的新特性支持最大320MHz带宽引入更高阶的4096-QAM调制技术MIMO 1616引入Multi-Link多链路机制Multi-RUPreamble Puncturing Wi-Fi 7的应用场景推荐阅读 Wi-Fi 7名词…

DevEco Studio 生成HPK文件

DevEco Studio 生成HPK文件 一、安装环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、生成HPK文件 生成的HPK文件存放在entry文件夹下。下图是未生成HPK的样式。 生成HPK:菜单Build->Build Hap(s)/APP(s)->Build Hap(s)…

Python使用分段函数拟合数据

Python使用分段函数拟合数据 前言前提条件相关介绍实验环境使用分段函数拟合数据代码实现输出结果 前言 由于本人水平有限,难免出现错漏,敬请批评改正。更多精彩内容,可点击进入Python日常小操作专栏、OpenCV-Python小应用专栏、YOLO系列专栏…

HCIA-H12-811题目解析(3)

1、【单选题】 以下关于路由器的描述,说法错误的是? 2、【单选题】某网络工程师在输入命令行时提示如下信息:Error:Unrecognized command foun at position.对于该提示信息说法正确的是? 3、【单选题】如下图所示的网络&#xf…

Vue3-03-reactive() 响应式基本使用

reactive() 的简介 reactive() 是vue3 中进行响应式状态声明的另一种方式; 但是,它只能声明 【对象类型】的响应式变量,【不支持声明基本数据类型】。reactive() 与 ref() 一样,都是深度响应式的,即对象嵌套属性发生了…

数据科学工作的20个Pandas函数(备忘)

Pandas 是数据科学社区中使用最广泛的库之一,它是一个强大的工具,可以进行数据操作、清理和分析。 本文将提供最常用的 Pandas 函数以及如何实际使用它们的样例。我们将涵盖从基本数据操作到高级数据分析技术的所有内容,到本文结束时&#xf…

还在为论文焦虑?免费AI写作大师帮你三分钟搞定

先来看1分钟的视频,对于要写论文的你来说,绝对有所值! 还在为写论文焦虑?免费AI写作大师来帮你三步搞定 第一步:输入关键信息 第二步:生成大纲 稍等片刻后,专业大纲生成(由于举例&am…

WPS没保存关闭了怎么恢复数据?3个方法,完成数据恢复!

“我今天在使用WPS时,突然有点急事出去了一趟,但是我忘记保存文档了,回来之后发现电脑自动关机了,我的文档也没了!这可怎么办呢?有什么办法可以找回这些数据吗?” 在快节奏的工作中,…

PyQt6 表单布局Form Layout (QFormLayout)

锋哥原创的PyQt6视频教程: 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计43条视频,包括:2024版 PyQt6 Python桌面开发 视频教程(无废话版…

Phong vs. BRDF

在深入探讨 BRDF 和照明模型的概念之前,我们将介绍一种用于模拟有光泽(glossy)表面(例如塑料球)外观的技术。 从那里开始,推广该技术将变得更加容易,这就是 BRDF 和照明或反射模型概念的全部内容…

mysql:用SHOW COLUMNS FROM显示一个表的列信息

可以使用命令SHOW COLUMNS FROM table_name;显示一个表的列信息,例如:

电工--半导体器件

目录 半导体的导电特性 PN结及其单向导电性 二极管 稳压二极管 双极型晶体管 半导体的导电特性 本征半导体:完全纯净的、晶格完整的半导体 载流子:自由电子和空穴 温度愈高,载流子数目愈多,导电性能就愈好 型半导体&…

Springboot内置Tomcat线程数优化

Springboot内置Tomcat线程数优化 # 等待队列长度,默认100。队列也做缓冲池用,但也不能无限长,不但消耗内存,而且出队入队也消耗CPU server.tomcat.accept-count1000 # 最大工作线程数,默认200。(4核8g内存…