【数据结构和算法】使用数组的结构实现链表(单向或双向)

news2024/5/18 16:40:44

上文我们通过结构体的结构实现了队列、以及循环队列的实现,我们或许在其他老师的教学中,只学到了用结构体的形式来实现链表、队列、栈等数据结构,本文我想告诉你的是,我们可以使用数组的结构实现链表、单调栈、单调队列

目录

前言

一、用数组结构的好处

1.数组的优缺点

2.链表的优缺点

3.总结

二、用数组实现链表

1.认识构造、初始化

2.将x插入到头结点

3.将x插入到第k次插入数值之后的位置

4.删除第k次插入的结点

三、完整代码演示

四、数组实现双向链表

1.初始化

2.在第k次插入的点的右边插入x

3.删除第k个点

五、完整代码


前言

你之前实现链表的形式,是不是这一种结构来实现

typedef struct ListNode {
	int data;
	struct ListNode* next;
}List;

但是我如果告诉你只需要这样两个数组就能模拟实现链表,你相信吗!!!

head	表示头节点
e[N]	表示存储结点数值的数组
ne[N]	表示结点的下一个结点的位置
idx   表示当前存储元素的位置   当前存储到哪里了就是

 接下来我们来实现单链表,以及双向链表

一、用数组结构的好处

我们在日常学习的过程中,老师教授给我们的都是以结构体的形式实现的链表,但是呢,比如我们要创建100000个结点,这样的话, 用结构体的话,时间太长,空间太大,反观数组,就显得很有优势了。

1.在搞算法的时候,使用数组的形式去模拟链表,会使得运算速度变快,更加适合写算法,打比赛的小朋友。

2.在笔试的适合,会更快的创建实现链表的基础功能,进行插入删除元素,并根据下标直接找到所需元素等

我们在来了解一下数组和链表的优缺点吧

1.数组的优缺点

认识数组:

数组是一种线性结构,存储的空间是内存连续的(物理连续),每当创建一个数组的时候,就必须先申请好一段指定大小的空间。(一次申请即可指定大小的空间)

优点:

由于内存连续这一特征,数组的访问速度很快,直到索引下标之后,可以实现O(1)的时间复杂度的访问。

缺点:

1.在任意位置删除和插入操作的时候,就会涉及到部分元素的移动,这样的话我们对于数组的任意位置的删除和插入的操作的时间复杂度为O(n)。

比如:

1>在i点后面插入数据,那么就需要i+1位置以及之后的元素,整体后移一位(for循环操作),然后再将插入的数据放在i+1的位置上

2>在i点之后删除元素,那么就需要,将i+1以及之后的元素,整体前移一位,总元素个数减一

以上是数组的优缺点,可以快速访问,达到O(1),但是在任意删除和插入元素的时候,会耗时间,达到O(n)。

2.链表的优缺点

认识链表

1.链表也是一种线性结构,但是他存储空间是不连续的(物理不连续,逻辑连续),链表的长度是不确定且支持动态扩展的。每次插入元素的时候,都需要进行申请新节点,然后赋值,插入链表中。

优点:
在插入数据或者删除数据的时候,只需要改变指针的指向即可,不需要类似于数组那样部分整体移动,整个过程不涉及元素的迁移,因此链表的插入和删除操作,时间复杂度为O(1)

缺点:

在查找任意位置的结点的数值域的时候,需要遍历,时间复杂度为O(n)

但是我们在任意位置插入或者删除元素的时候,需要查找这个指定的元素的结点位置,所以综合起来,链表的插入和删除仍为O(n)。

3.总结

无论数组还是链表,查找的时间复杂度都是O(n),查找都要挨个遍历,直到找到满足的条件的数据为止,所以对于链表,如果没有给定,指针的地址,只是要插入删除第N位元素的时候,加上查找,综合起来时间复杂度为O(n)。

但是我们如果以数组的形式来实现链表,那么插入删除指定元素位置的时候,是不是就更加简便了呢,在第N位插入删除元素的时候,直接以O(1)的时间复杂度找到该位置结点,然后再由于链表的删除插入都是O(1)的,所以整个删除或插入操作,综合时间复杂度为O(1),比普通链表快很多。

二、用数组实现链表

1.认识构造、初始化

我们先由图示了解初始化的时候的准备工作

我们使用c++会更加方便理解,因为c++支持用变量来定义数组

初始化代码:

//使用c++更简单,先用c++的形式实现
const int N = 100010;
int head, e[N], ne[N], idx; //全局变量
void init() {
	head = -1;
	idx = 0;//进行初始化的操作,idx为当前链表中(数组)最后一个元素(末尾),下标位置
}

2.将x插入到头结点

就是所谓的链表中的头部插入

图示:

实际上和普通链表的头插一样,只是流程next指针换成了ne[N]数组的形式,记录的是下一结点的数值。

代码如下:

void add_to_head(int x) {
	e[idx] = x;//将x数值存入到e[]数组中
	ne[idx] = ne[head];//将idx新插入的结点的下一个位置存储到ne[idx]中  ,全局变量 ne以及n数组初始化为0
	head = idx;
	idx++;
}

3.将x插入到第k次插入数值之后的位置

图示:

我们要说明一个问题,ne[N]这个数组存放的数值,是不需要管的,因为不管是add还是remove,插入还是删除结点,都不会重复,实际上,e[ne[head]]是得到head结点下一个结点的数值,ne[]数组只作为,下标使用。 

我们是在第k次插入的之后的位置插入x,但是与此同时 ,此时的idx成为新的第k次插入数据下标,也就是说,再次对第k次插入数值之后的位置插入的x,实际上是在上一次的新插入的结点之后进行插入

图示:

代码如下:

//在第k个插入的数字之后插入数据
void add(int k, int x) {
	e[idx] = x;
	ne[idx] = ne[k];
	ne[k] = idx;
	idx++;
}

4.删除第k次插入的结点

//将下标为k的点后面的点删掉
void remove(int k, int ne[]) {
	ne[k] = ne[ne[k]];//表示k的下一个位置(ne)为下一个位置的下一个位置,这样跳过了原来的ne[k]结点
}//使用的时候应该是  删除的是k之后的点

直接跳过即可,和链表类似

三、完整代码演示

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>


const int N = 100010;
int n, e[N], ne[N], idx, head;


//初始化
void init() {
	head = -1;
	idx = 0;
}

//头插
void add_to_head(int x) {
	e[idx] = x;
	ne[idx] = head;
	head = idx;
	idx++;
}

//在第k个插入的数字之后插入数据
void add(int k, int x) {
	e[idx] = x;
	ne[idx] = ne[k];
	ne[k] = idx;
	idx++;
}
//删除第k的插入的数据
void remove(int k) {
	ne[k] = ne[ne[k]];
}

int main()
{
	init();
	add_to_head(1);
	add_to_head(2);
	add_to_head(3);
	add_to_head(4);
	add_to_head(5);
	add(2-1, 10);
	add(2-1, 2);
	add(2-1, 3);
	add(2-1, 4);
	add(2-1, 5);
	add_to_head(50);
	for (int i = head; i != -1; i=ne[i]) {
		printf("%d ", e[i]);
	}
	printf("\n");
	for (int i = head; i != -1; i = ne[i]) {
		printf("%d ", ne[i]);
	}
	return 0;
}

四、数组实现双向链表

1.初始化

//初始化
// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int m;
const int N = 100010;
int e[N], l[N], r[N], idx;
void init() {
	//0表示为左端点,1表示为右端点
	r[0] = 1;
	l[1] = 0;
	idx = 2;//从2开始
}

我们设定,用e[N]数组来记录数据,在用 l[N] 、 r[N]数组表示结点的左右指针,一开始,0表示为左端点,1表示右端点,然后r、l两个数组记录,数值下标从2开始

e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点

2.在第k次插入的点的右边插入x

//在第k次插入的点的右边插入x;

void add(int k, int x) {
	e[idx] = x;//数值x给当前idx位置的e数组存储
	r[idx] = r[k];//将新节点的左右两端分别连接k的后一个结点r[k]和k本身
	l[idx] = k;
	l[r[k]] = idx;//然后将k的右端点的左端点连接idx
	r[k] = idx;//最后将k的右端点连接idx
}

3.删除第k个点

//删除第k个点
void remove(int k) {
	//就是将k的左端点和右端点相互连接
	l[r[k]] = l[k];
	r[l[k]] = r[k];
}

五、完整代码

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<assert.h>
//使用数组的形式实现双向链表


//e[N]	表示存储结点的数值
//l[N]	表示当前结点的左结点位置
//r[N]	表示当前结点的右节点位置
//idx	表示当前结点存储的位置

//初始化
int m;
const int N = 100010;
int e[N], l[N], r[N], idx;
void init() {
	//0表示为左端点,1表示为右端点
	r[0] = 1;
	l[1] = 0;
	idx = 2;//从2开始
}

//在第k次插入的点的右边插入x;

void add(int k, int x) {
	e[idx] = x;//数值x给当前idx位置的e数组存储
	r[idx] = r[k];//将新节点的左右两端分别连接k的后一个结点r[k]和k本身
	l[idx] = k;
	l[r[k]] = idx;//然后将k的右端点的左端点连接idx
	r[k] = idx;//最后将k的右端点连接idx
}

//删除第k个点
void remove(int k) {
	//就是将k的左端点和右端点相互连接
	l[r[k]] = l[k];
	r[l[k]] = r[k];
}

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

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

相关文章

2022最火科技~AIGC

2022年最火的信息科技~AIGC 人工智能内容生成 趣讲大白话&#xff1a;输入几个词&#xff0c;立刻生成机器创造的内容 ************** 从人工智能决策 走向 人工智能生成 人工智能决策&#xff1a;自动驾驶、抖音推荐算法 人工智能生成内容&#xff1a;即AI Generated Conten…

【算法练习】两个链表的第一个公共节点

描述输入两个无环的单向链表&#xff0c;找出它们的第一个公共结点&#xff0c;如果没有公共节点则返回空。&#xff08;注意因为传入数据是链表&#xff0c;所以错误测试数据的提示是用其他方式显示的&#xff0c;保证传入数据是正确的&#xff09;数据范围&#xff1a; 0n≤1…

下一代编解码技术Ali266在视频超高清领域的应用展望

超高清与各领域的需求融合和创新正在发生。 2022年是一个体育大年&#xff0c;众多世界级体育赛事通过视频直播、转播等形式给观众带来畅爽的观看体验。 2022年北京冬奥会&#xff0c;实现了奥运会历史上首次赛事全程4K制作播出&#xff0c;并在开幕式上提供了8K超高清公共信号…

安全多方计算之五:零知识证明(从入门到入土。。)

零知识证明1. 简介2. 零知识证明的例子2.1 向红绿色盲证明红球、绿球2.2 数独的零知识证明2.3 三染色问题的零知识证明2.4 Quisquater-Guillou 零知识协议3. ElGamal加密的零知识证明3.1 ElGamal加密的已知明文证明3.2 ElGamal加密的二选一零知识证明3.3 ElGamal加密的1-out-of…

MATLAB - 查找数据峰值

语法如下&#xff1a; pks findpeaks(data) [pks,locs] findpeaks(data) [pks,locs,w,p] findpeaks(data) [___] findpeaks(data,x) [___] findpeaks(data,Fs) [___] findpeaks(___,Name,Value) findpeaks(___)where&#xff0c;pks是峰值返回值&#xff0c;locs是数据索…

特斯拉 FSD 背后的技术(1)—从 BEV 到占用网络

在今年 tesla 的 AI Day 给我这个业余自动驾驶爱好者给留下了深刻印象&#xff0c;在看过之后&#xff0c;通过收集资料对其中阐述的技术进行简单的了解&#xff0c;在这里拿出来跟大家分享一下&#xff0c;有点长&#xff0c;所以划分了一下 3 个部分。从 BEV 到占用网络激进无…

chrome查看网页性能

1 Performance 1.1 打开开发者工具&#xff08;cmdshiftc&#xff09; 1.2 打开Performance面板&#xff0c;点击录制按钮&#xff08;开始录制&#xff09; 1.3 刷新页面&#xff0c;再次点击录制按钮&#xff08;结束录制&#xff09; 录制按钮高亮&#xff0c;表示录制中…

算法训练营DAY47|198.打家劫舍、213.打家劫舍II 、337.打家劫舍III

这一期到了打家劫舍的专题&#xff0c;说是专题但实际上只有一期&#xff0c;而且只有三道题&#xff0c;我们把这三道题放在一起讲&#xff0c;第一道题简单一些&#xff0c;后两道略有不同方向上的难度。但总体来看第一次做可能有一点难想到思路&#xff0c;其实代码实现还是…

百度、字节终于不再相互“抄袭”

文|智能相对论作者|佘凯文“百度和字节跳动&#xff0c;分道扬镳”乍一看挺标题党的&#xff0c;这两个互联网巨头从没在一起过&#xff0c;又何来“分道扬镳”之说&#xff1f;不急&#xff0c;且往下看。众所周知&#xff0c;当前国内互联网行业&#xff0c;早已不是当初啥也…

【链表->环形链表】

诸如环形链表的结构有&#xff1a;尾节点链接向各个节点的链表&#xff0c;也可链向自己&#xff0c;称为环形链表。只要链表中带有环&#xff0c;均可称为环形链表。下面通过一些例题来详细讲述环形链表&#xff1a;1.给你一个链表的头节点 head &#xff0c;判断链表中是否有…

python进阶——人工智能实时目标跟踪

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a;lqj_本人的博客_CSDN博客-微信小程序,前端,vue领域博主lqj_本人擅长微信小程序,前端,vue,等方面的知识https://blog.csdn.net/lbcyllqj?spm1000.2115.3001.5343 哔哩哔哩欢迎关注&…

Apollo planning之参考线平滑算法

Apollo studio 官网&#xff1a;Apollo开发者社区 (baidu.com) 目录 1 参考线的作用 2 参考线的数据结构 2.1 ReferenceLine的数据结构 2.2 ReferencePoint的数据结构 3 参考线处理流程 ​4 参考线平滑算法 4.1 算法分类 4.2 参考线平滑算法流程 4.2.1 AnchorPoint …

Learning C++ No.1

引言&#xff1a; 北京时间 2023/2/1/20:38&#xff0c;三天没写博客&#xff0c;打字量严重下滑&#xff0c;这两天是看剧时间&#xff0c;我发现看电视剧有时候还是非常的让人无法自拔的&#xff0c;一天追完一部30集的电视剧&#xff0c;我还是很佩服我自己的&#xff0c;现…

我愿称之为天花板的【Python自动化测试开发文档】—自动化测试开发平台实战

我愿称之为天花板的【Python自动化测试开发文档】—自动化测试开发平台实战 目录&#xff1a;导读 本文以下内容均适合这类人群 包含的模块&#xff1a; 第一章&#xff1a;Python 零基础入门 第二章&#xff1a; Web 应用框架 第三章&#xff1a;自动化平台开发 第四章…

React的学习笔记-(Bilibili天禹老师)

React的特点 采用组件化模式,声明式编码,提高开发效率和组件复用率在React Native中可以使用React语法进行移动端开发(IOS和Android)使用虚拟DOM优秀的Diffing算法,尽量减少与真实DOM的交互 babel用处 es6 > es5jsx > js 1.你好,react 注意引入顺序 <!DOCTYPE h…

图扑软件 | 虚拟电厂负荷控制系统可视化

前言 随着国家“双碳”及“构建以新能源为主体的新型电力系统”等目标的提出&#xff0c;清洁化、数字化越来越成为电力系统面临的迫切需求&#xff0c;负控系统的发展对电力营销现代化建设具有重要的意义。 负控管理系统是一个着眼于全面加强电力信息管理的&#xff0c;集负…

Query 聚类

为了提高阅读体验&#xff0c;请移步到&#xff1a;Query 聚类背景搜索系统优化长尾 query。想了解一下长尾 query 长什么样&#xff1f;大体上都有几类&#xff1f;最好能归类&#xff0c;一类一类处理。Query 数据源&#xff1a;包含“什么”&#xff0c;“怎么”&#xff0c…

儿童台灯怎么选对眼睛好?2023开学必买的儿童台灯

l 通过国家卫健委发布的数据——2020年儿童青少年总体近视率高达52.7% l 爱尔眼科视光研究所的数据——6岁儿童中45%已失去远视储备&#xff0c;6-10岁近视度数增长最快 l 孩童近视程度的发展之外&#xff0c;让人猝不及防 l 在光照环境中&#xff0c;能给孩子们提供最好的阅…

力扣468验证IP地址C++判断合法IP字符串

目录前言题目描述解题思路主功能函数分类大框架判断IPv4是否合法判断IPv6是否合法其余小边界条件(调试后得)完整代码前言 这是一道常见的笔试面试题,我找实习已经碰到两次了&#xff0c;和矩阵的乘法出现频率一样高&#xff0c;你校招要是全程没遇到可以过来打我;(这道题大厂面…

SAP IFRS 17 面向服务架构详细解析(包含分类账规则)

经过漫长的旅程,国际会计准则委员会 (IASB) 于 2017 年 5 月发布了 IFRS 17“保险合同”(IFRS 17)。IFRS 17 取代了 2004 年发布的 IFRS 4。总体目标是提供一个更加透明和全球签发保险合同的实体之间保险合同的统一会计模型。在 IFRS 17 标准发布三年后,IASB 于 2020 年 6 月…