【数据结构学习笔记】19:跳表(Skip List)

介绍

跳表是一个能在 O ( n l o g n ) O(nlogn) O(nlogn)时间完成查找、插入、删除的数据结构,相比于树形结构优点就是很好写(所以也用于实现Redis ZSet)。其核心思想就是维护一个元素有序的,能随机提升索引层数的链表。最下面一层就是一个普通的链表,存了所有的元素,而每次提升索引高度都一定会从最下面一层开始提升连续的若干层,因此从最上面的层到最下面的层,索引一定是从稀疏到稠密,所以在查询的时候就能从上层开始,很快的跳过一些元素,再向下一层走,逐渐定位到元素的位置。

实现思路

结构

固定跳表层数后,跳表的每个结点(存某个元素)都在每一层有一个next指针,指向这一层的下一个结点。

为了查询方便,设定一个虚拟头结点,这个虚拟头节点作为查询的起始节点,每一层会指向实际的这一层的起始节点。

内部操作:find

引入一个特殊的内部操作,用于定位结点在每一层的位置,不管是接下来要删除这个结点,还是在这个结点附近(前或者后)插入一个元素结点都能借用这个操作方便的找到它。

考虑到每一层都是一个单向链表,所以find操作一定是返回目标结点在每一层的前置结点。

因为这个操作希望得到的是一个Node指针的数组,这个数组会在下一步的操作(插入/删除/查询)中被用到,所以可以给这个跳表引入一个prev数组缓存这个信息,每次使用前直接清空就可以了。

查询操作:search

find得到目标元素的prev数组,然后就能找到最下面那层的结点,即prev[0]->next[0],根据结点是否存在以及是否是要找的元素就可以得到search的结果了。

添加操作:add

因为跳表是有序的,所以一定会按序添加到指定的位置上。先先find得到目标元素的prev数组,然后从最下层开始向上,除了最下面那层一定要插入,上面的层i如果(连续且随机地)需要派生这层的索引,就根据prev[i]是该节点在第i层的前置结点,在此层按照链表的方式插入这个索引就可以了。

删除操作:erase

先做一遍serach操作,确认要删除的元素存在,且构造好了prev数组,接下来从下层向上,对于每一层i,按照链表的方式判断要删除的结点在此层存在索引,就将索引删除。因为索引从下到上是连续存在的,所以删到找不到索引就一定已经删干净了,最后记得回收结点即可。

例题:LeetCode 1206. 设计跳表

class Skiplist {
private:static const int MAX_LEVEL = 8;struct Node {int val;Node** next;Node(int _val) :val(_val) {next = new Node*[MAX_LEVEL];memset(next, NULL, sizeof(Node*) * MAX_LEVEL);}} *head, **prev;void find(int target, Node** prev) {Node* p = head;for (int i = MAX_LEVEL - 1; i >= 0 ; i -- ) {while (p->next[i] && p->next[i]->val < target) p = p->next[i];prev[i] = p;}}public:Skiplist() {this->head = new Node(-1);this->prev = new Node*[MAX_LEVEL];}~Skiplist() {delete this->head;delete[] this->prev;}bool search(int target) {memset(prev, NULL, sizeof(Node*) * MAX_LEVEL);find(target, prev);auto p = prev[0]->next[0];return p && p->val == target;}void add(int num) {memset(prev, NULL, sizeof(Node*) * MAX_LEVEL);find(num, prev);auto p = new Node(num);for (int i = 0; i < MAX_LEVEL; i ++ ) {p->next[i] = prev[i]->next[i];prev[i]->next[i] = p;if (rand() % 2) break;}}bool erase(int num) {memset(prev, NULL, sizeof(Node*) * MAX_LEVEL);find(num, prev);auto p = prev[0]->next[0];if (!p || p->val != num) return false;for (int i = 0; i < MAX_LEVEL && prev[i]->next[i] == p; i ++ )prev[i]->next[i] = p->next[i];delete p;return true;}
};/*** Your Skiplist object will be instantiated and called as such:* Skiplist* obj = new Skiplist();* bool param_1 = obj->search(target);* obj->add(num);* bool param_3 = obj->erase(num);*/

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

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

相关文章

DeepSeek-V3技术报告

摘要 https://arxiv.org/pdf/2412.19437v1 我们介绍DeepSeek-V3&#xff0c;这是一个强大的混合专家&#xff08;MoE&#xff09;语言模型&#xff0c;具有6710亿个总参数&#xff0c;每个token激活37亿个参数。为了实现高效推理和经济实惠的训练&#xff0c;DeepSeek-V3采用了…

【spring mvc】文件上传、下载

文件上传&#xff0c;存储至本地目录中 一、代码1、工具类&#xff08;敏感后缀过滤&#xff09;2、文件上传&#xff0c;存储至本地3、文件下载 二、效果演示1、上传1.1、postMan 请求1.2、上传效果 2、下载2.1、下载效果 一、代码 1、工具类&#xff08;敏感后缀过滤&#x…

CryptoMamba:利用状态空间模型实现精确的比特币价格预测

“CryptoMamba: Leveraging State Space Models for Accurate Bitcoin Price Prediction” 论文地址&#xff1a;https://arxiv.org/pdf/2501.01010 Github地址&#xff1a;https://github.com/MShahabSepehri/CryptoMamba 摘要 预测比特币价格由于市场的高波动性和复杂的非线…

dockerfile2.0

dockerfile实现lnmp nginx centos7 mysql centos7 php centos7 自定义镜像来实现整个架构 cd /opt mkdir nginx mysql php cd nginx 拖入nginx和wordpress vim Dockerfile vim nginx.conf ↓ worker_processes 1; events {worker_connections 1024; } http {include …

C#类型转换

C#是静态类型的语言&#xff0c;变量一旦声明就无法重新声明或者存储其他类型的数据&#xff0c;除非进行类型转换。本章的主要任务就是学习类型转换的知识。类型转换有显式的&#xff0c;也有隐式的。所谓显式&#xff0c;就是我们必须明确地告知编译器&#xff0c;我们要把变…

智能物流升级利器——SAIL-RK3576核心板AI边缘计算网关设计方案(一)

近年来&#xff0c;随着物流行业智能化和自动化水平不断提升&#xff0c;数据的实时处理与智能决策成为推动物流运输、仓储管理和配送优化的重要手段。传统的集中式云平台虽然具备强大计算能力&#xff0c;但高延迟和带宽限制往往制约了物流现场的即时响应。为此&#xff0c;我…

【算法篇】前缀和

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;算法笔记仓 前缀和是一种常用于处理数组区间求和问题的技巧。它可以用来减少重复计算&#xff0c;使得多次查询区间和的时间复杂度从 O(n) 降低到 O(1) 目录 1. 一维模版2. 二维模版3. 除自身以外数…

第R4周:LSTM-火灾温度预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 文章目录 一、代码流程1、导入包&#xff0c;设置GPU2、导入数据3、数据集可视化4、数据集预处理5、设置X&#xff0c;y6、划分数据集7、构建模型8、定义训练函…

机组存储系统

局部性 理论 程序执行&#xff0c;会不均匀访问主存&#xff0c;有些被频繁访问&#xff0c;有些很少被访问 时间局部性 被用到指令&#xff0c;不久可能又被用到 产生原因是大量循环操作 空间局部性 某个数据和指令被使用&#xff0c;附近数据也可能使用 主要原因是顺序存…

Windows图形界面(GUI)-QT-C/C++ - Qt图形绘制详解

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 Qt绘图基础 QPainter概述 基本工作流程 绘图事件系统 paintEvent事件 重绘机制 文字绘制技术 基本文字绘制 ​编辑 高级文字效果 基本图形绘制 线条绘制 ​编辑 形状绘制 …

mapbox进阶,添加绘图控件

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图控…

client-go 的 QPS 和 Burst 限速

1. 什么是 QPS 和 Burst &#xff1f; 在 kubernetes client-go 中&#xff0c;QPS 和 Burst 是用于控制客户端与 Kubernetes API 交互速率的两个关键参数&#xff1a; QPS (Queries Per Second) 定义&#xff1a;表示每秒允许发送的请求数量&#xff0c;即限速器的平滑速率…

WeakAuras NES Script(lua)

WeakAuras NES Script 修星脚本字符串 脚本1&#xff1a;NES !WA:2!TMZFWXX1zDxVAs4siiRKiBN4eV(sTRKZ5Z6opYbhQQSoPtsxr(K8ENSJtS50(J3D7wV3UBF7E6hgmKOXdjKsgAvZFaPTtte0mD60XdCmmecDMKruyykDcplAZiGPfWtSsag6myGuOuq89EVDV9wPvKeGBM7U99EFVVVV33VFFB8Z2TJ8azYMlZj7Ur3QDR(…

【make】makefile 函数全解

目录 makefile简介函数全解介绍相关链接字符串处理函数subst 函数—字符串替换patsubst 函数 — 模式字符串替换strip 函数 — 去空格findstring 函数 — 查找字符串filter 函数 — 过滤器filter-out 函数 — 过滤器sort 函数 — 排序word 函数 — 取单词wordlist函数 — 取一串…

Android 15应用适配指南:所有应用的行为变更

Android系统版本适配&#xff0c;一直是影响App上架Google Play非常重要的因素。 当前Google Play政策规定 新应用和应用更新 必须以 Android 14&#xff08;API 级别 34&#xff09;为目标平台&#xff0c;才能提交到Google Play。现有应用 必须以 Android 13&#xff08;AP…

Java Agent(三)、ASM 操作字节码入门

目录 1、前言 2、什么是ASM&#xff1f; 2.1、工作流程 2.2、ASM集合核心API 2.1.1、ClassReader 2.1.2、ClassWriter 2.1.3、 ClassVisitor 2.1.4、MethodVisitor 2.1.5、 FieldVisitor 2.1.6、Opcodes 3、简单示例 3.1、maven依赖 3.2、hello world 3.3、执行结…

MySQL数据库(SQL分类)

SQL分类 分类全称解释DDLData Definition Language数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库&#xff0c;表&#xff0c;字段&#xff09;DMLData Manipulation Language数据操作语言&#xff0c;用来对数据库表中的数据进行增删改DQLData Query Languag…

[微服务]redis数据结构

介绍 我们常用的Redis数据类型有5种&#xff0c;分别是&#xff1a; StringListSetSortedSetHash 还有一些高级数据类型&#xff0c;比如Bitmap、HyperLogLog、GEO等&#xff0c;其底层都是基于上述5种基本数据类型。因此在Redis的源码中&#xff0c;其实只有5种数据类型。 …

PyQt5

PyQt5 环境搭建安装 pycharm安装 PyQt5 打包成exe安装 pyinstaller打包 报错进程已结束&#xff0c;退出代码-1073740791&#xff08;0xC0000409&#xff09; 环境搭建 安装 pycharm 安装 PyQt5 pip install pyqt5 -i https://pypi.tuna.tsinghua.edu.cn/simplepip install …

高级运维:shell练习2

1、需求&#xff1a;判断192.168.1.0/24网络中&#xff0c;当前在线的ip有哪些&#xff0c;并编写脚本打印出来。 vim check.sh #!/bin/bash# 定义网络前缀 network_prefix"192.168.1"# 循环遍历1-254的IP for i in {1..254}; do# 构造完整的IP地址ip"$network_…