快速了解什么是跳跃表(skip list)

什么是跳跃表(skip list)

跳跃表(Skip List)是一种概率性的数据结构,它通过在多层链表的基础上添加“快速通道”来提高搜索效率。跳跃表的效率可以与平衡树相媲美,即在平均和最坏的情况下,查找和插入操作都可以在 O(logn) 的时间复杂度内完成,其中 n 是跳跃表中的元素数量。

跳跃表的工作原理:

  • 多层链表:跳跃表包含多个层次,每个层次都是一个有序的链表。底层是完整的有序链表,包含所有的元素。每一层(除了底层)都是下面一层的一个“子集”,其中包含了选定的元素和指向这些元素的指针。
  • 节点晋升:当在跳跃表中插入一个新元素时,这个元素首先被插入到底层链表中。然后,通过一种随机过程(例如抛硬币),决定这个元素是否“晋升”到上一层链表。这个过程可能会继续,导致元素可能会出现在多个层次中。
  • 快速查找:查找元素时,从最高层开始,快速前进直到无法继续前进为止(因为下一个元素大于要查找的元素),然后下降到下一层继续查找。这样,可以跳过大量不需要的元素,从而加速查找过程。

为什么使用跳跃表?

跳跃表之所以有效,是因为它们利用了概率平衡来减少维护平衡所需的工作量,与平衡树相比,跳跃表在实现上更为简单,且不需要复杂的旋转操作。Redis选择使用跳跃表作为有序集合的一部分,是因为它们非常适合于实现范围查询和有序遍历,这些操作在有序集合中非常常见。

跳跃表与内存使用:

虽然跳跃表会使用多个层次来存储指向相同数据的指针,但由于这些指针指向的是相同的数据元素,所以元素的实际数据并不会被复制多份,因此并不会造成数据本身的重复存储。指针和层次结构是额外的开销,但这是为了获得在对数时间内执行搜索、插入和删除操作的能力。

举个例子:

1、多层链表

想象一下,你有一串编号的盒子排成一行,每个盒子都代表一个元素,编号越大的盒子放在越后面。现在,如果你想找到特定编号的盒子,你可能需要从第一个盒子开始,一个接一个地查看,直到找到你要的盒子。

这就像跳跃表的底层链表:每个盒子都直接连接到下一个,你需要逐个检查。

现在,假设我们在这些盒子之上加了一层,这一层只包含一些选定的盒子,并且每个选中的盒子都有一个指针指向它在下一层的对应盒子。这些选中的盒子让你可以跳过那些没有被选中的盒子,因此如果你在上层找不到你要的盒子,你可以下降到底层继续寻找。

这相当于跳跃表的第二层,其中一些元素被“晋升”到了这一层。

继续这个过程,我们可以添加更多的层,每个层次比下面的层次包含更少的元素。在顶层,可能只有几个盒子。当你开始搜索时,你会从顶层开始,利用这些“快速通道”迅速逼近你的目标编号。一旦你在某一层上不能再接近目标了,你就下降到下一层继续搜索。这样,你可以快速跳过那些不相关的编号,直到找到你要的盒子。

在实际的跳跃表中,元素是否晋升到更高的层级是通过随机化过程决定的,这样可以保证结构的平衡,而不需要复杂的调整。

以下是一个形象的跳跃表示例:

层 3: 1 ------------------------------> 9

层 2: 1 --------> 5 --------> 7 -------> 9

层 1: 1 -> 3 -> 5 -> 6 -> 7 -> 8 -> 9
  • 底层(层 1)含有所有元素(盒子)。
  • 第二层(层 2)含有编号为 1, 5, 7, 9 的盒子,可以跳过 3、6、8。
  • 第三层(层 3)只含有编号为 1 和 9 的盒子,提供了从开始到结束的快速通道。

如果你想找编号为 7 的盒子,从层 3 开始,发现你需要下降到层 2,因为层 3 里没有编号为 7 的盒子。

在层 2,你从 5 直接跳到 7,省去了检查 3 和 6 的需要。

这样,你就高效地找到了目标。

2、节点晋升

在跳跃表中,节点的晋升是通过随机化过程来实现的,以确保整个跳跃表的平衡。一个常见的方法是使用抛硬币的方式来决定一个节点是否晋升到上一层,这个方法称为“硬币翻转”(coin flipping)。

节点晋升过程的步骤如下:

  1. 插入节点:首先,新的节点被插入到跳跃表的最底层链表中。
  2. 抛硬币:然后,进行硬币翻转来决定这个节点是否晋升到上一层。硬币翻转是一个随机过程,通常是50%的概率来决定。
  3. 晋升节点:如果硬币翻转结果是正面(例如“头”),则节点晋升到下一个层级。
  4. 重复晋升:对晋升到新层级的节点再次进行硬币翻转,决定它是否继续晋升。这个过程重复进行,直到翻转结果为反面(例如“尾”)为止。

假设你正在插入一个新节点A,并且你已经将其插入到了底层链表中。现在,你开始进行硬币翻转:

  • 第一次翻转:得到“头”,节点A晋升到第2层。
  • 第二次翻转:再次得到“头”,节点A继续晋升到第3层。
  • 第三次翻转:这次得到“尾”,晋升过程停止,节点A在第3层停留。

通过这个随机晋升的过程,跳跃表自然地形成了多层结构,顶层的节点数目会比底层少,这样就可以快速跳过大量的节点,提高搜索效率。

这个随机化的过程有助于跳跃表在没有任何调整的情况下保持平衡,因为晋升的过程并不依赖于具体的数值或插入的顺序,而是依赖于概率。这个过程保证了跳跃表的操作在平均情况下都是高效的。

需要深入了解点这里

-----------------------------------------------------------------我是分割线--------------------------------------------------------------

看完了觉得不错就点个赞或者评论下吧,感谢!!!

如果本文哪里有误随时可以提出了,收到会尽快更正的
 

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

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

相关文章

Xcode15更新内容

参考博客: 【WWDC 2023】Xcode 15 更新内容 文章目录 1. xcode15起,项目内创建的图片可以使用点语法访问2.2. UIKit项目也可以使用预览功能3. Xcode新增标签功能4.Log分类 1. xcode15起,项目内创建的图片可以使用点语法访问 2.2. UIKit项目也…

Linux C语言(8)

1、指针 1.1 概念 指针就是地址指针是一种数据类型,是一种保存地址的数据类型int是一种数据类型,是一种保存整数的数据类型 1 2 3 4float是一种数据类型,是一种保存浮点数的数据类型 3.14 1.2 什么是地址 内存分配的最小单位是字节&#xf…

【Leetcode】【数据结构】【C语言】判断两个链表是否相交并返回交点地址

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode *tailAheadA;struct ListNode *tailBheadB;int count10;int count20;//分别找尾节点,并顺便统计节点数量:while(tailA){tailAtailA->next;c…

flutter开发报错The instance member ‘widget‘ can‘t be accessed in an initializer

文章目录 问题描述问题原因解决方法 问题描述 The instance member ‘widget’ can’t be accessed in an initializer. 问题原因 “The instance member ‘widget’ can’t be accessed in an initializer” 错误是因为在初始化器列表中(constructor initializer…

Shell 脚本介绍及应用案例

目录 Shell传递参数 $特殊符号含义 示例: Shell运算符 关系运算符 文件运算符 示例: Shell 流程控制 if判断 格式: 示例: 结果: for循环 格式: 示例: 结果: w…

Webpack 中 Plugin 的作用是什么?常用 plugin 有哪些?

说说webpack中常见的Plugin?解决了什么问题?- 题目详情 - 前端面试题宝典 1、plugin 的作用 Plugin 是一种计算机应用程序,它和主应用程序互相交互,以提供特定的功能。 是一种遵循一定规范的应用程序接口编写出来的程序&#…

如何上传自己的Jar到Maven中央仓库

在项目开发过程中,我们常常会使用 Maven 从仓库拉取开源的第三方 Jar 包。本文将带领大家将自己写好的代码或开源项目发布到 Maven中央仓库中,让其他人可以直接依赖你的 Jar 包,而不需要先下载你的代码后 install 到本地。 注册帐号 点击以…

【MySQL篇】数据库角色

前言 数据库角色是被命名的一组与数据库操作相关的权限,角色是权限的集合。因此,可以为一组具有相同权限的用户创建一个角色,使用角色来管理数据库权限可以简化授权的过程。 CREATE ROLE:创建一个角色 GRANT:给角色授…

进程(3)——进程优先级与环境变量【Linux】

进程(3)——进程优先级与环境变量【Linux】 一. 进程如何在cpu中如何执行1.1进程在CPU中的特性1.2 寄存器1.2.1 进程的上下文 二. 进程优先级2.1 如何查看进程优先级2.2 修改进程的优先级2.2.1 NI值2.2.2 修改方法 三. 环境变量3.1 什么是环境变量&#…

华为ICT——第六章:深度学习和卷积神经网络/详篇

目录 1:深度学习卷积的重要概念: 2:CNN核心思想——局部感知: CNN核心思想——参数共享: 3:卷积层的功能: 4:不同深度的卷积层提取的特征: 5:卷积效果——…

【公益案例展】火山引擎公益电子票据服务——连接善意,共创美好

‍ 火山引擎公益案例 本项目案例由火山引擎投递并参与数据猿与上海大数据联盟联合推出的 #榜样的力量# 《2023中国数据智能产业最具社会责任感企业》榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 捐赠票据是慈善组织接受捐赠后给捐赠方开具的重要凭证&…

saleae逻辑分析仪在win10上的安装: 驱动安装失败的解决办法

1. 安装 安装64位的:Logic Setup 1.1.16 (64-bit).exe 选择安装目录: 安装其间,如果弹出驱动安装对话框,要选择信任并安装驱动。 安装结束,打开软件,是未连接的状态。 此时打开电脑的设备管理器&#xff…

程序员男盆友给自己做了一款增进感情的小程序

前言 又是无聊的一天,逛GitHub的时候发现一个给女朋友做了一个互动微信小程序,据说女朋友更爱自己了,所以当晚。。。。给自己做了丰盛的晚餐,我当即点开立马开发粘贴复制起来,想到做的小程序可以和未来的女朋友增进感…

基于React开发的chatgpt网页版(仿chatgpt)

在浏览github的时候发现了一个好玩的项目本项目,是github大神Yidadaa开发的chatgpt网页版,该开源项目是跨平台的,Web / PWA / Linux / Win / MacOS都可以访问。非常有意思,本人就部署了一套,喜欢的同学可以体验一番。 …

快速教程|如何在 AWS EC2上使用 Walrus 部署 GitLab

Walrus 是一款基于平台工程理念的开源应用管理平台,致力于解决应用交付领域的深切痛点。借助 Walrus 将云原生的能力和最佳实践扩展到非容器化环境,并支持任意应用形态统一编排部署,降低使用基础设施的复杂度,为研发和运维团队提供…

干货 | 接口自动化测试分层设计与实践总结

接口测试三要素: 参数构造 发起请求,获取响应 校验结果 一、原始状态 当我们的用例没有进行分层设计的时候,只能算是一个“苗条式”的脚本。以一个后台创建商品活动的场景为例,大概流程是这样的(默认已经是登录状态下)&#…

FMCW雷达论文速览 | TRS 2023, 基于FMCW雷达的多天线高精度测距算法及性能分析

注1:本文系“最新论文速览”系列之一,致力于简洁清晰地介绍、解读最新的顶会/顶刊论文 TRS 2023 | High Accuracy Multi-antenna Ranging Algorithm and Performance Analysis for FMCW Radar 论文原文:https://ieeexplore.ieee.org/document/10309162 Z. Xu, S. Qi and P. Zh…

webgoat-(A1)SQL Injection

SQL Injection (intro) SQL 命令主要分为三类: 数据操作语言 (DML)DML 语句可用于请求记录 (SELECT)、添加记录 (INSERT)、删除记录 (DELETE) 和修改现有记录 &#xff…

springboot本地启动多个模块报错:Address already in use: JVM_Bind

目录 背景解决方法 背景 环境: jdk1.8 idea 2019.2.4idea本地启动多个模块联调时,提示报错: 错误: 代理抛出异常错误: java.rmi.server.ExportException: Port already in use: 9090; nested exception is: java.net.BindException: Addre…

SpringBoot系列之集成Redission入门与实践教程

Redisson是一款基于java开发的开源项目,提供了很多企业级实践,比如分布式锁、消息队列、异步执行等功能。本文基于Springboot2版本集成redisson-spring-boot-starter实现redisson的基本应用 软件环境: JDK 1.8 SpringBoot 2.2.1 Maven 3.2…