C++跳跃表个人理解

news2025/1/11 17:51:27

一、概念

跳跃表是一种基于有序链表的扩展,简称跳表,其就是使用关键节点作为索引的一种数据结构。

可以通过以下方式更快查找到有序链表的某一节点:

利用类似索引的思想,提取出链表中的部分关键节点。比如,给定一个长度为7的有序链表,节点值依次是1->2->3->5->6->7->8,那么我们可以取出所有值为奇数节点的作为关键点。

此时如果要插入一个值是4的新节点,不再需要和原节点8,7,6,5,3逐一比较,只需要比较关键节点8,5,3.

确定了新节点在关键节点中的位置(3和5之间),就可以回到原链表,迅速定位到对应的位置,然后进行插入。

 

 多层关键节点多层索引

对于跳跃表来说,当然不能只会有一层索引节点,那么可以进一步提取索引,在索引层中提取出一层新的索引。

有了二级索引之后,新的节点可以先和2级索引进行比较,确定大体范围;然后再和1级索引比较;最后回到原链表,找到并插入对应位置。

 层级极限是什么?

当节点足够多的时候,不止能提取出二级索引,还可以向高层次提取,保证每一层是上一层节点数的一半。

提取的极限:同一层只有两个节点的时候,因为一个节点没有比较的意义。

怎么从新节点当中选取一部分提到上一层?

当大量的新节点通过逐层比较,最终插入到原链表之后,上层的索引节点会变得不够用。这时候需要从新节点当中选取一部分提到上一层。

使用随机决定新节点是否提升层级,每次向上提升一层的概率是百分之50.

为什么要随机决定新节点是否层级提升?

(1)跳跃表删除和添加节点是不可预测的,很难用一种有效地算法来保证跳跃表的索引部分始终均匀。

(2)采用随机法虽然不能保证索引绝对均匀分布,却可以让大体趋于均匀。

二、时间复杂度分析

跳跃表将新节点(删除节点)和各层索引节点逐一进行比较,确定原链表的插入或者删除位置。时间复杂度为O(logn)。

跳跃表的插入和删除操作需要的时间复杂度和原始链表一样,都为O(1)。

三、跳跃表的特征

一个完整的跳跃表,应该具有以下特征:

1、一个跳表应该有几个层(level)组成。

2、跳表的第一层包含所有的元素。

3、每一层都是一个有序的链表。

4、如果元素x出现在第i层,则所有比i小的层都包含x。

5、每个节点包含key及其对应的value和一个指向同一层链表的下个节点的指针数组(next[i])。

四、跳跃表和红黑树性能比较

目前,经常使用的平衡数据结构有:B树、红黑树、AVL树等。跳跃表是平衡树一种替代的数据结构,但是和红黑树不相同的是,跳跃表对于平衡的实现是基于一种随机化的算法,跳跃表的插入和删除工作是比较简单的。

1、查询性能:

跳跃表和红黑树的查询时间复杂度都为O(logn)。

2、插入和删除性能:

跳跃表在进行插入和删除操作时,相对来说,更容易调整结构,也就是可能需要在索引层中增加或者删除相应节点。

红黑树在进行插入和删除操作时,就需要进行旋转或者颜色调度操作,相对复杂一些。

3、空间复杂度:

跳跃表的空间复杂度相对高一些,需要额外的空间来存储多层指针。平均情况下O(n),最糟糕的情况下O(nlogn)。

红黑树空间开销相对跳跃表来说会低。O(n)。

4、应用场景:

如果要在高并发的场景下,频繁进行插入和删除节点,那么跳跃表可能更合适一些。

如果对空间性能要求较高,那么可以去使用红黑树。

五、代码实现

#include<iostream>
#include<time.h>
#include<assert.h>
#include<stdlib.h>
using namespace std;
#define MAX_L 5//跳跃表最大层数
 
//节点结构
struct Node
{
	int key;//节点的值
	Node* next[];//多层链表节点
};
//跳跃表结构
struct Skiplist
{
	int level;//跳跃表层数
	Node* head;
};
//创建节点
Node* CreateNode(int level, int key)
{
	Node* p = (Node*)malloc(sizeof(Node) + level * sizeof(Node*));
	if (nullptr == p)
	{
		return nullptr;
	}
	for (int i = 0; i < level; ++i)
	{
		p->next[i] = nullptr;
	}
	p->key = key;
	return p;
}
//创建表
Skiplist* CreateList()
{
	Skiplist* s = (Skiplist*)malloc(sizeof(Skiplist));
	if (nullptr == s)
	{
		return nullptr;
	}
	s->level = 0;
	Node* nh = CreateNode(MAX_L + 1, 0);
	if (nullptr == nh)
	{
		free(s);
		return nullptr;
	}
	s->head = nh;
	return s;
}
//生成新节点的级数
int random()
{
	int level = 0;
	while (level <= MAX_L && rand() < RAND_MAX / 2)
	{
		++level;
	}
	return level;
}
//向跳跃表中插入元素
bool InsertNode(Skiplist* s, int key)
{
	if (nullptr == s) return false;
	//第一步,查找到在每层待插入位置,更新update数组
	Node* update[MAX_L + 1] = {};
	Node* q = nullptr, * p = s->head;
	//找到每一层插入前的一个节点,更新update数组
	for (int i = s->level; i >= 0; --i)
	{
		while (p->next[i] != nullptr && p->next[i]->key < key)
		{
			p = p->next[i];
		}
		update[i] = p;
	}
	p = p->next[0];
	if (p != nullptr && p->key == key)
	{
		return true;
	}
	//第二步,随机产生一个层数
	int newlevel = random();
 
	//新产生的节点层数比原跳跃表大
	if (newlevel > s->level)
	{
		for (int i = s->level + 1; i <= newlevel; ++i)
		{
			update[i] = s->head;
		}
		s->level = newlevel;
	}
	//第三步,从高往下插入
	p = CreateNode(newlevel + 1, key);
	if (nullptr == p)
	{
		return false;
	}
	//根据update数组在每一层中插入新节点
	for (int i = newlevel; i >= 0; --i)
	{
		p->next[i] = update[i]->next[i];
		update[i]->next[i] = p;
	}
	return true;
}
//删除跳跃表中的元素
bool DeleteNode(Skiplist* s, int key)
{
	Node* update[MAX_L + 1] = {};
	Node * p = s->head;
	//找到每一层待删除元素前的一个节点,放入update数组中
	for (int i = s->level; i >= 0; --i)
	{
		while (p->next[i] != nullptr && p->next[i]->key < key)
		{
			p = p->next[i];
		}
		update[i] = p;
	}
	Node* q = p->next[0];
	assert(q != nullptr);
	//判断q是否为待删除的节点 
	if (q==nullptr && q->key != key)
	{
		return false;
	}
	for (int i = s->level; i >= 0; --i)
	{
		if (update[i]->next[i]==q)
		{
			update[i]->next[i] = q->next[i];
			if (s->head->next[i] == nullptr)
			{
				s->level--;
			}
		}
	}
	free(q);
	return true;
}
void Print(Skiplist* s)
{
	Node* p = nullptr;
	for (int i = s->level; i >= 0; --i)
	{
		p = s->head->next[i];
		cout << "level:" << i << endl;
		while (p != nullptr)
		{
			cout << "key:" << p->key << " ";
			p = p->next[i];
		}
		cout << endl;
	}
}
void FreeList(Skiplist* s)
{
	if (nullptr == s)
	{
		return;
	}
	Node* q = s->head;
	Node* next = nullptr;
	while (q != nullptr)
	{
		next = q->next[0];
		free(q);
		q = next;
	}
	free(s);
}
int main()
{
	Skiplist* mylist = CreateList();
	for (int i = 1; i < 5; ++i)
	{
		InsertNode(mylist, i);
	}
	DeleteNode(mylist, 3);
	Print(mylist);
	free(mylist);
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言 ——— 指针笔试题(中篇)

指针加减整数和解引用的笔试题 笔试题1&#xff1a; int a[5][5]; int(*p)[4]; p a;printf("%p %d", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);问&#xff1a;打印的结果为&#xff1f;&#xff08;分别以 %d 和 %p 的形式打印&#xff09; …

十六、maven git-快速上手(智慧云教育平台)

&#x1f33b;&#x1f33b; 目录 一、概述及项目管理工具介绍1.1 项目介绍1.2 maven 介绍及其配置1.2.1 maven 介绍1.2.2 maven 下载与配置 1.3 pom 中常见标签的使用1.4 后端项目环境的搭建1.5 Git 简介1.6 Git 的基本使用1.6.1 码云的注册与仓库创建1.6.2 上传代码到码云仓库…

【2024】InfluxDB v2 介绍和安装使用(1)

目录&#x1f4bb; 一、介绍1、时序数据库介绍特点&#xff1a;常见的时序数据库时序库受欢迎度排名 2、InfluxDB介绍**InfluxDB 1.x 和 2.0 的主要区别**InfluxDB行协议 二、docker安装 InfluxDB v2三. Web UI常用功能介绍以及使用1、页面介绍2、功能使用2.1、创建bucket2.2、…

如何设计一个测试用例

前言&#x1f440;~ 上一章我们介绍了什么是软件测试以及软件测试的一些基础概念&#xff0c;今天来聊聊如何设计一个测试用例&#xff0c;涉及到黑盒测试的测试方法 基于需求进行测试用例的设计 基于需求的具体设计方法 等价类 边界值 判定表法 正交表法 场景设计法 …

智能ai对话软件都有哪些?分享4款!

在科技日新月异的今天&#xff0c;智能AI对话软件正以前所未有的速度改变着我们的生活方式与工作模式。它们不仅仅是冷冰冰的代码堆砌&#xff0c;更是拥有理解、学习乃至创造能力的智能伙伴&#xff0c;为人类社会带来了前所未有的便捷与乐趣。那么&#xff0c;究竟有哪些智能…

git安装和使用(托管服务 分支 克隆)超细教程

先来了解一下知识 下载与安装 (默认安装,下一步即可) 下载地址&#xff1a; https://git-scm.com/download 下载完成后可以得到如下安装文件&#xff1a; 双击下载的安装文件来安装Git。安装完成后在电脑桌面&#xff08;也可以是其他目录&#xff09;点击右键&#xff0c;如…

动态规划-斐波那契数列

一. 什么是动态规划 dp一般是需要前面状态的值的问题。比如&#xff0c;解决一个问题需要很多步骤&#xff0c;且步骤之间相关联&#xff0c;后一个步骤的推导需要前一个步骤的结论。而我们所做的就是&#xff0c;将这个带求解的问题分成若干步骤&#xff0c;将每个步骤答案保…

成为git砖家(10): 根据文件内容生成SHA-1

文章目录 1. .git/objects 目录2. git cat-file 命令3. 根据文件内容生成 sha-14. 结语5. References 1. .git/objects 目录 git 是一个根据文件内容进行检索的系统。 当创建 hello.py, 填入 print("hello, world")的内容&#xff0c; 并执行 git add hello.py gi…

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——1到手测试

本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——1到手测试 ​ 大家好&#xff0c;今天给大家带来的是购买到小车或者说RDK X3之后直接快速体验&#xff0c;今天主要围绕官方的快速入门手册进行逐步测试 1.知识补充1 ​ 在这里首先要给新手小白补充几…

JVM结构、架构与生命周期总结

【1】JVM结构 不同厂商的JVM产品 &#xff1a; 厂商JVMOracle-SUNHotspotOracleJRocketIBMJ9 JVM阿里Taobao JVM HotSpot VM是目前市面上高性能虚拟机的代表作之一。它采用解释器与即时编译器并存的架构。 在今天&#xff0c;Java程序的运行性能早已脱胎换骨&#xff0c;已…

数据上新 | 景联文科技推出高质量方言音文对数据集,驱动方言语音大模型技术革新

中国电信人工智能研究院&#xff08;TeleAI&#xff09;正式对外发布星辰超多方言语音识别大模型。这是业内首个支持30种方言自由混说的语音识别大模型&#xff0c;也是目前国内支持最多方言的语音识别大模型。 方言语音大模型具有广泛的应用场景&#xff0c;可以应用于语音助手…

1.1.9创建应用

1.在全局配置文件下找到urls.py进行路由配置 配置路由要指明哪个应用&#xff0c;和写好模块导入的函数 2.找到路由要启动的应用&#xff0c;在应用里找到视图函数进行设计 path&#xff08;‘url模式/“&#xff0c;视图函数&#xff09; 注意第五部没有/ 1.1.110路由匹配模…

小阿轩yx-KVM+GFS 分布式存储系统构建 KVM 高可用

小阿轩yx-KVMGFS 分布式存储系统构建 KVM 高可用 案例分析 案例概述 使用 KVM 及 GlusterFS 技术&#xff0c;结合起来实现 KVM 高可用利用 GlusterFS 分布式复制卷对 KVM 虚拟机文件进行分布存储和冗余 分布式复制卷 主要用于需要冗余的情况下把一个文件存放在两个或两个…

刚起步的海外仓怎么选WMS系统,要注意什么

对于刚起步的海外仓企业来说&#xff0c;最紧要的事情就是把核心业务打磨平稳&#xff0c;形成核心竞争力&#xff0c;才能在激烈的竞争中赢得一席之地。 而要实现这个目的&#xff0c;WMS海外仓系统的引入当然是必要的一环&#xff0c;不过因为刚起步&#xff0c;业务和资源都…

AI产品经理的职责与能力:将AI技术转化为实际价值

一、AI产品经理的职责 发现和解决问题&#xff1a;AI产品经理需要具备敏锐的洞察力&#xff0c;能够发现用户需求和痛点&#xff0c;并提出相应的解决方案。传递价值给用户&#xff1a;AI产品经理需要确保产品能够满足用户的需求&#xff0c;提供价值&#xff0c;并提升用户体…

大模型之语言大模型技术

本文作为大模型综述第二篇,介绍语言大模型基本技术。 近年来,在 Transformer 架构基础上构建的预训练语言模型为自然语言处理领域带来了一系列突破式进展,成为人工智能主流技术范式。预训练语言模型采用“预训练+微调”方法,主要分为两步: 1)将模型在大规模无标注数据上…

No static resource favicon.ico.问题解决

一&#xff0c;问题 Spring Boot项目调用接口时报错 org.springframework.web.servlet.resource.NoResourceFoundException: No static resource favicon.ico. at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpReques…

餐饮卫生数字化防线:EasyCVR明厨亮灶/透明厨房/阳光厨房视频监管方案

近期有新闻报道&#xff0c;某互联网大厂办事处发生了一起大规模食物中毒事件&#xff0c;导致近60人住院。餐饮食品卫生安全直接关系到人民群众的身体健康和生命安全&#xff0c;是社会关注的焦点。 传统的监管方式往往依赖于人力巡查和抽检&#xff0c;存在效率低、覆盖面窄…

企业邮箱安全稳定吗?

企业邮箱安全稳定吗&#xff1f;企业邮箱通过GDPR等国际标准保护数据&#xff0c;采用加密技术、反垃圾邮件、身份验证等措施确保安全。服务器全球分布&#xff0c;灾难恢复和备份确保稳定。Zoho邮箱提供多种版本和注册流程&#xff0c;支持邮件协作、备份与恢复等功能。 一、…

成为一名月薪 2 万的 web 安全工程师需要掌握哪些技能?

现在 web 安全工程师比较火&#xff0c;岗位比较稀缺&#xff0c;现在除了一些大公司对学历要求严格&#xff0c;其余公司看中的大部分是能力。 有个亲戚的儿子已经工作 2 年了……当初也是因为其他的行业要求比较高&#xff0c;所以才选择的 web 安全方向。 资料免费分享给你…