c++实现跳表
原理
跳表(Skip List) 是一种随机化数据结构,用于高效查找、插入和删除,尤其适用于有序数据集合。相比链表,跳表通过多层索引结构加速查找,期望时间复杂度接近 O(logn)。跳表的主要思想是:
- 底层链表存储所有数据元素,保持有序。
- 上层链表是稀疏索引,用于跳过部分节点,减少遍历的长度。
结构图
下面是一个跳表的结构示意:
Level 3: [1] ----------------> [9]
Level 2: [1] -----> [4] -----> [9]
Level 1: [1] -----> [4] -----> [7] -----> [9]
Level 0: [1] -> [2] -> [4] -> [5] -> [7] -> [8] -> [9]
如上图所示:
- 每一层都是一个有序链表。
- 每一层的节点是下一层的子集,存储重要的中间节点,形成分层索引。
- 查找过程:从最高层开始,先向右移动,如果目标值超出范围,则向下移动到下一层。重复此过程直到找到目标节点。
优缺点
优点:
- 插入、删除和查找的期望时间复杂度为 O(logn)。
- 实现简单,比红黑树和AVL树更容易理解和维护。
缺点:
- 需要额外的空间存储索引层节点。
代码示例(c++)
下面是一段简单的 C++ 跳表实现,包括节点结构定义、插入、查找和显示功能。
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
using namespace std;class Node {
public:int value;vector<Node*> forward; // 每层的前向指针Node(int val, int level) : value(val), forward(level + 1, nullptr) {}
};class SkipList {
private:int maxLevel; // 跳表的最大层数float probability; // 晋升概率Node* header; // 头节点int currentLevel; // 当前跳表的层数public:SkipList(int maxLevel, float probability) : maxLevel(maxLevel), probability(probability), currentLevel(0) {header = new Node(-1, maxLevel); // 头节点初始化为-1srand(time(nullptr)); // 初始化随机数种子}// 随机生成节点的层数int randomLevel() {int lvl = 0;while ((rand() / double(RAND_MAX)) < probability && lvl < maxLevel) {lvl++;}return lvl;}// 插入新节点void insert(int value) {vector<Node*> update(maxLevel + 1);Node* current = header;// 从最高层向下查找插入位置for (int i = currentLevel; i >= 0; i--) {while (current->forward[i] && current->forward[i]->value < value) {current = current->forward[i];}update[i] = current;}// 在底层插入节点的位置current = current->forward[0];// 如果节点不存在,则插入新节点if (!current || current->value != value) {int lvl = randomLevel();if (lvl > currentLevel) {for (int i = currentLevel + 1; i <= lvl; i++) {update[i] = header;}currentLevel = lvl;}Node* newNode = new Node(value, lvl);for (int i = 0; i <= lvl; i++) {newNode->forward[i] = update[i]->forward[i];update[i]->forward[i] = newNode;}cout << "Inserted value: " << value << " at level: " << lvl << endl;}}// 查找节点bool search(int value) {Node* current = header;for (int i = currentLevel; i >= 0; i--) {while (current->forward[i] && current->forward[i]->value < value) {current = current->forward[i];}}current = current->forward[0];return current && current->value == value;}// 打印跳表结构void display() {for (int i = currentLevel; i >= 0; i--) {Node* current = header->forward[i];cout << "Level " << i << ": ";while (current) {cout << current->value << " ";current = current->forward[i];}cout << endl;}}
};int main() {SkipList skipList(4, 0.5); // 最大层数为4,晋升概率为0.5skipList.insert(3);skipList.insert(6);skipList.insert(7);skipList.insert(9);skipList.insert(12);skipList.insert(19);cout << "Skip List Structure:" << endl;skipList.display();cout << "Search 7: " << (skipList.search(7) ? "Found" : "Not Found") << endl;cout << "Search 4: " << (skipList.search(4) ? "Found" : "Not Found") << endl;return 0;
}
代码解析
- Node 类:
- 表示跳表中的节点,包含节点的值和指向不同层节点的指针向量
forward
。
- 表示跳表中的节点,包含节点的值和指向不同层节点的指针向量
- SkipList 类:
- 实现了跳表的主要功能,包括插入、查找和显示结构。
randomLevel
:用于随机生成节点的层数,控制索引的稀疏程度。insert
:插入元素到跳表中,如果新节点的层数超过当前最大层数,则更新索引。search
:查找目标值是否存在。
- 主函数:
- 初始化跳表并插入若干元素,测试插入和查找功能。
运行结果
Inserted value: 3 at level: 0
Inserted value: 6 at level: 1
Inserted value: 7 at level: 2
Inserted value: 9 at level: 0
Inserted value: 12 at level: 1
Inserted value: 19 at level: 3
Skip List Structure:
Level 3: 19
Level 2: 7 19
Level 1: 6 12 19
Level 0: 3 6 7 9 12 19
Search 7: Found
Search 4: Not Found
总结
- 时间复杂度:查找、插入、删除的期望时间复杂度为 O(logn)O(\log n)O(logn)。
- 空间复杂度:O(nlogn)O(n \log n)O(nlogn),因为每个节点可能会出现在多层中。
跳表的实现简单且高效,常用于 Redis 等数据库的有序集合。
相关文章:
c++实现跳表
原理 跳表(Skip List) 是一种随机化数据结构,用于高效查找、插入和删除,尤其适用于有序数据集合。相比链表,跳表通过多层索引结构加速查找,期望时间复杂度接近 O(logn)。跳表的主要思想是: …...

新探索研究生英语读写教程pdf答案(基础级)
《新探索研究生英语读写教程》的设计和编写充分考虑国内研究生人才培养目标和研究生公共英语的教学需求, 教学内容符合研究生认知水平, 学术特征突出;教学设计紧密围绕学术阅读、学术写作和学术研究能力培养;教学资源立体多元&…...

管道与共享内存
一,命名管道 管道的限制就是他只能在有血缘关系(父子进程)的进程中,允许互相访问,这是有局限性的,所以我们想在毫无关系的进程中允许他们相互访问,这就是命名管道的定义。 总结:命名…...
ES 自定义排序方式
es默认score是根据query的相关度进行打分的,具体打分机制可以参见:官方文档。如果召回时既希望有相关性又能根据其他信息进行排序。 例如小红书搜索的时候,可能既希望有召回相关度又能根据热度信息(如果喜欢、收藏等等参数去进行召…...
在vue中,编写一个li标签同时使用v-for和v-if,谁的优先级更高
在 Vue 中,v-if 和 v-for 是两个常用的指令,但它们的优先级不同。当二者一起使用时,v-for 的优先级高于 v-if。这意味着,v-for 会先执行,即使列表中的某些元素不满足 v-if 条件,它们仍会被遍历和渲染。 由…...
Java 后端开发面试题及其答案
以下是一些常见的 Java 后端开发面试题及其答案,涵盖了 Java 基础、面向对象、并发、多线程、框架等多个方面: 1. Java 中的基本数据类型有哪些? 答案: Java 中的基本数据类型有 8 种: int:32 位整数lon…...

C++,STL 045(24.10.24)
内容 1.对set容器的大小进行操作。 2.set容器的交换操作。 运行代码 #include <iostream> #include <set>using namespace std;void printSet(set<int> &s) {for (set<int>::iterator it s.begin(); it ! s.end(); it){cout << *it <…...

二叉树习题其五【力扣】【算法学习day.12】
前言 书接上篇文章二叉树习题其四,这篇文章我们将基础拓展 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一…...

【数据库】Mysql的锁类型
Mysql中的锁机制主要是为了保证数据的一致性和完整性,在并发的情况下起着至关重要的作用。其中锁的类型主要是分为以下几种: 按照粒度分类 全局锁:对于整个数据库实例进行枷锁,加锁后整个实例就处于只读的状态。局锁通常用于需要…...

自媒体短视频制作素材下载网站推荐,让创作更简单
随着自媒体行业的火爆,视频质量要求也越来越高。想要找到无版权的高清视频素材并不容易,但别担心!今天为大家整理了5个国内外高质量的素材网站,让你轻松获取自媒体短视频素材,快收藏起来吧! 蛙学网 蛙学网是…...

Altium Designer 入门基础教程(五)
本文章继续接着《Altium Designer 入门基础教程(四)》的内容往下介绍: 七、AD画板的整个流程步骤 I.集成库的制作 AD元件库有2种:1、原理图元件库SCH.LIB 2、印刷电路板(PCB)元件库 PCB.LIB 印刷电路…...
Java题集练习3
Java题集练习3 1 什么时候用instanceof instanceOf关键字主要用于判断一个对象是否为某个类的子类或是接口的实例,通常用于类型转换和运行时类型判断的场景,比如继承和多态中。比如,创建一个Animal类及其子类Cat和Cat子类Hat,可…...

【部署篇】Haproxy-01安装部署(源码方式安装)
一、HAProxy概述 HAProxy是一款免费、快速且可靠的代理软件,提供高可用性、负载均衡,支持TCP和HTTP应用代理,HAProxy凭借其卓越的性能和灵活性,成为众多知名网站和系统的首选代理软件。 核心特点: 高性能…...

开拓鸿蒙测试新境界,龙测科技引领自动化测试未来
在当今科技舞台上,鸿蒙 OS 以非凡先进性强势登场,打破传统操作系统格局,为软件测试领域带来全新机遇与艰巨挑战。 一、鸿蒙 OS 的辉煌崛起 (一)壮丽发展历程与卓越市场地位 鸿蒙 OS 的发展如波澜壮阔的史诗。2023 年…...

Java项目-基于springboot框架的自习室预订系统项目实战(附源码+文档)
作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 开发运行环境 开发语言:Java数据库:MySQL技术:SpringBoot、Vue、Mybaits Plus、ELementUI工具:IDEA/…...

调整数组奇偶数顺序
今天给大家分享一道题目,要求我们输入一个数组,将全部奇数放在偶数前面(无需比较大小),下面是我写的代码 这个方法比使用三个数组进行数据传输要节省不少程序运行时间,缺点是使用了较多的while循环…...
Electron调用nodejs的cpp .node扩展【非安全】
Electron调用nodejs的cpp .node扩展【非安全】 环境: electron: 30.1.1 nodejs: 20.14.0前言 Electron中可以非常容易的调用nodejs的js代码,但是对于cpp .node扩展需要一定的配置才能调用,下面介绍一种最简单的cpp扩展的调用方法ÿ…...

一文了解AOSP是什么?
一文了解AOSP是什么? AOSP基本信息 基本定义 AOSP是Android Open Source Project的缩写,这是一个由Google维护的完全免费和开放的操作系统开发项目。它是Android系统的核心基础,提供了构建移动操作系统所需的基本组件。 主要特点 完全开源…...

ffmpeg视频边缘模糊,打造梦幻般的视觉效果!
在视频编辑的世界里,细节决定成败。边缘模糊效果是一种强大的工具,可以让你的作品瞬间提升质感。通过简单的命令,你可以轻松实现视频边缘的柔和化处理,创造出梦幻般的视觉效果。 想象一下,当你将一段普通的视频应用边…...

[Wireshark] 使用Wireshark抓包https数据包并显示为明文、配置SSLKEYLOGFILE变量(附下载链接)
前言 wireshark安装包 链接:https://pan.quark.cn/s/febb28f57c01 提取码:fUCQ 链接失效(可能会被官方和谐)可评论或私信我重发 chrome与firefox在访问https网站的时候会将密钥写入这个环境变量SSLKEYLOGFILE中,在wir…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...