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…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
