『数据结构』跳跃表

2023-11-04

本篇博客主要介绍一下跳跃表的原理和简单实现。

什么是跳跃表?


增加了向前指针的链表叫做跳表,跳表全称跳跃表,简称跳表。

  • 跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表
  • 跳表在原有的有序链表上面增加了多级索引,通过索引实现快速查找
  • 跳表不仅能提高搜索性能,同时也可以提供插入和删除操作的性能

跳跃表的原理


我们知道,在一个单链表中如果想要根据值来查找一个元素,时间复杂度为 O ( N ) O(N) O(N)即使该链表是有序的,也不能通过二分的方式来降低时间复杂度
在这里插入图片描述
如上图,如果我们要查找值为52的元素的结点,我们必须从头结点开始,循环遍历知道找到值为52的结点,也就是最后一个结点,一共比较8次(-INF,负无穷不算)

我们有没有什么办法来减少访问的次数呢?我们可以试着去开辟一条捷径去访问52
在这里插入图片描述
如上图,我们要查找值为52的结点只需要在L2层查找4次即可找到
在这个结构中,查询值为47的结点只需要查询5次先在L2层查找47,查询4次后找到52,因为链表是有序的,所以我们回退到39,然后去L1层去查找,查询一次就查到了47,所以一共需要查找5次。

我们能不能让查找值为52结点的次数再减少呢?我们可以考虑再开辟一条捷径
在这里插入图片描述
如上图,我们查找值为52的结点只需要在L3层查找2次即可
查找元素47仍然是最耗时的,需要查询5次先在L3层查询2次,再在L2层查询2次,最后到L1层查询一次

从上面的查找过程看,这种思想和二分的思想非常相似,我们再将结构完善一下,最终结构如下
在这里插入图片描述
我们可以看出最耗时的访问仍然是访问值为47的结点一共需要查询6次。L4层访问52,L3访问25、52,L2访问39、52,L1访问47,共6次

跳跃表的时间复杂度


在这里插入图片描述
如果有n个元素,因为是二分,所以层数就应该是 l o g 2 N log_2N log2N层,再加上自身的1层

  • 以上图为例,如果是4个元素,那么分层为L4和L3,再加上本身的L2,一共3层;如果是8个元素,那么就是3 + 1层。

最耗时间的查询自然是访问所有层数,耗时 l o g 2 N + l o g 2 N log_2N + log_2N log2N+log2N,即 2 l o g 2 N 2log_2N 2log2N。为什么是 2 l o g 2 N 2log_2N 2log2N呢?

  • 我们以访问47来分析一下,查询到47要访问所有的分层,每个分层都要访问2个元素,中间元素和最后一个元素。

所以跳跃表的时间复杂度 O ( l o g 2 N ) O(log_2N) O(log2N)

跳跃表的实现分析


从上面跳跃表的时间复杂度的分析我们可以看出,该跳跃表是比较理想的
但是如果想要在跳跃表中插入或者删除一个元素呢?比如我们插入一个元素22、23、24…,自然是在L1层插入,但是这些元素在L1层插入之后,那么如何调整L2层和L3层的连接来维持这个比较理想的跳跃表呢
我们知道,平衡二叉搜索树的调整是一件令人非常头疼的事,左旋、右旋、左右旋;而调整一个理想的跳跃表将是一个比调整平衡二叉搜索树还复杂的操作
但是这里,我们不需要通过复杂的操作调整连接来维护这样完美的跳跃表有一种基于概率统计的插入算法,也能得到时间复杂度为 O ( l o g 2 N ) O(log_2N) O(log2N)的查询效率,这种跳跃表是比较实用的。

跳跃表的插入分析


从理想跳跃表,我们可以看出,L2层元素的数量是L1层元素数量 1 / 2 1/2 1/2L3层元素数量是L2层元素数量 1 / 2 1/2 1/2,依次类推。从这里,我们可以想到,只要在插入时尽量保证上一层的元素个数是下一层元素 1 / 2 1/2 1/2,我们的跳跃表就能成为理想的跳跃表
那么如何在插入时保证上一层元素的个数是下一层元素个数 1 / 2 1/2 1/2呢?我们可以通过抛硬币的方式来决定

  • 假设元素e要插入跳跃表,很显然,L1层肯定要插入元素e
  • 那么L2层要不要插入e呢?我们希望上层元素个数是下层元素个数的 1 / 2 1/2 1/2,所以我们有 1 / 2 1/2 1/2的概率希望e插入L2层,那么抛一下硬币吧,正面朝上就插入,反面就不插入
  • 那么L3到底要不要插入e呢?相对于L2层,我们还是希望 1 / 2 1/2 1/2的概率插入,可以继续抛硬币
  • 依次类推,元素e插入第i层的概率就是 ( 1 / 2 ) i (1/2)^i (1/2)i。这样,我们就能在跳跃表中插入一个元素了。
  • 如果插入元素的数量较小,结果很可能不是一个理想的跳跃表。但是如果元素数量非常大,根据概率学我们可以知道,最终的表结构肯定非常接近于理想的跳跃表

插入操作依赖于查询操作,所以插入操作的时间复杂度同样为 O ( l o g 2 N ) O(log_2N) O(log2N)

跳跃表的删除分析


删除操作和普通的链表删除操作完全一样,直接删除元素,然后调整一下删除元素后的指针就可以了
删除操作同样依赖于查询操作,所以删除操作的时间复杂度同样也是 O ( l o g 2 N ) O(log_2N) O(log2N)

代码实现


代码实现可参考

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

『数据结构』跳跃表 的相关文章

随机推荐

  • linux红帽8怎么安yum,RedHat Linux 8本地Yum源配置方法

    1 挂载系统光盘到 mnt cdrom目录 mkdir p mnt cdrom mount dev sr0 mnt cdrom 2 设置系统启动后将光盘自动挂载到 mnt cdrom echo dev sr0 mnt cdrom iso96
  • 电商数据分析实战第一篇——客户消费行为分析

    一 分析背景 为了提高店铺的收益 进行准确的客户运营策略 使用店铺201910至202002的销售数据进行分析 根据客户的消费趋势 消费习惯把握客户的消费现状和心理 挖掘出高价值用户群体 完善销售运营策略 简单说明一下 客户分析包括基本属性
  • Upload LABS Pass-8

    第八关在后端使用了黑名单 并过滤了大小写 点以及空格 但并未过滤数据流 我们使用代理拦截请求 在文件后缀名中添加数据流 绕过黑名单 准备一个 8 php 文件 内容为一句话木马 上传 8 php 文件 并使用代理 此处使用 Burp Sui
  • JSON对象转换成字符串 相互转换 的几种方式

    在最近的工作中 使用到JSON进行数据的传递 特别是从前端传递到后台 前台可以直接采用ajax的data函数 按json格式传递 后台Request即可 但有的时候 需要传递多个参数 后台使用request进行接收 有时传递了几个数值 还好
  • 嵌套和递归使用模板类

    嵌套和递归使用模板类 模板栈 模板数组 栈中嵌套数组 数组中嵌套栈 数组中嵌套数组 模板栈 pragma once include
  • 计算机网络——网络层

    这篇文章是计算机网络系列文章的第三篇 计算机网络 物理层 计算机网络 数据链路层 计算机网络 网络层 计算机网络 传输层 计算机网络 应用层 序言 计算机网络中的网络层在当今的社会起到了什么作用 现在的互联网通信 远程办公和远程教育 电子商
  • 基于Dragonboard 410c进行开发的远程遥控机器人(三)

    前面说过 买的camera的夹层板要直接连到410c开发板上 这样96boards 就没有接口去连接了 无奈 智能自己飞线了 开始还担心 这样连接板子会不会出问题 经过最终的验证 发现是可以的 完全没有影响 接下来看一下最后的验证 图 远程
  • 安卓keytool获取不到签名文件的MD5

    目前通过 keytool list v keystore xxx jks 这种方法获取签名的md5时 只能显示SHA1和SHA256 不显示md5 解决办法 1 先将自己的keystore配置进app下的build gradle中 2 打开
  • 关键字参数和可选参数

    通常Fortran的实参和形参的参数数量以及类型必须是匹配的 但是如果过程接口是显式的 那么就可以改变参数表中调参数的顺序 或为过程的某些iochengde形参特别指定实参 通过将过程放在模块中 并在调用程序中用use关联访问模块 可以显式
  • C#中的BeforeFieldInit

    今天学习设计模式中的单例模式 无意间发现了这个标志BeforeFieldInit 于是简单地搜索了一下 总结出如下内容 The C specification states The static constructor for a clas
  • Doris--基础--11--动态分区

    Doris 基础 11 动态分区 1 介绍 对表级别的分区实现生命周期管理 TTL 减少用户的使用负担 1 1 功能 动态添加分区 动态删除分区 1 2 原理 在某些使用场景下 用户会将表按照天进行分区划分数据 在没有动态分区功能的时候 用
  • 2021第十二届蓝桥杯大赛软件赛省赛C/C++ 大学B组试题B杨辉三角形

    这题目很简单 问题是细节处理处理很重要 在蓝桥杯省赛中你只要搞对一两道题目就有省三了 实施代码 include
  • 做PPT设计半年赚8万,我是怎样做到的?

    下班做PPT 半年赚8万是什么感觉 你好 我是佳佳 一个用PPT兼职赚钱的宝妈 我现在每天抽2个小时 坐在电脑前 把各种素材像拼图一样拼接一下 像这样 然后把成稿投稿到设计平台 就能赚到钱 你是不是觉得 我是个职业设计师 挺厉害的 不是的
  • java 抽象类初始化_java-抽象类初始化

    我有一个抽象类 abstract class Shape public String color public Shape public void setColor String c color c public String getCol
  • 脚本自动化部署docker微服务,取代Jenkins

    由于Jenkins容器化部署 容器容器之间拷贝文件及其繁琐 如果在Jenkins部署在系统外层也需要配置复杂的流程才能实现微服务的自动化部署 本文主要通过脚本方式取代Jenkins实现自动化部署 脚本方式简单快捷 可以快速实现微服务部署 升
  • MyBatis 快速学习01:第一个程序

    目录 MyBatis简介 什么是MyBatis 为什么需要MyBatis MyBatis框架部署 项目目录结构 搭建实验数据库 创建maven项目 添加mybatis依赖 编写mybatis配置文件 编写MyBatis工具类 创建实体类 编
  • 旧版本Ubuntu安装magick出现undefined symbol的解决思路

    太长不看版 magick的安装需要底层的imagemagick支持 Ubuntu16 04由于版本老旧 安装的旧版imagemagick无法使用 使用spack自己安装新版 可以解决编译问题 果子老师向我求助 让我帮忙安装一个R包 magi
  • 与或非逻辑符号_基本逻辑运算

    今天我给大家分享的是逻辑运算 因为在实际中 我们遇到的逻辑问题是多种多样的 所以我跟大家唠叨一下我自己对逻辑运算的理解分享给各位 逻辑运算 与运算 与运算就是相当于乘法口诀 两个数相乘的结果 也可以理解为输入有0 则输出为0 逻辑表达式 F
  • javascript原生项目:剑网三

    javascript原生项目 剑网三 技术 html css javascript 页面 欢迎页 游戏列表页 充值页 登录页 项目效果 ps 项目源码文件评论区见
  • 『数据结构』跳跃表

    本篇博客主要介绍一下跳跃表的原理和简单实现 什么是跳跃表 增加了向前指针的链表叫做跳表 跳表全称跳跃表 简称跳表 跳表是一个随机化的数据结构 实质就是一种可以进行二分查找的有序链表 跳表在原有的有序链表上面增加了多级索引 通过索引实现快速查