数组模拟实现单链表快速操作

前言:我们都知道链表的一般模式是由结构体加指针来实现的,但是在实际的比赛中,结构体指针来实现链表的操作并不常用,原因是因为我们在增加节点时需要开辟新的内存,而比赛时给出的样例大多都是十几万个数据,就只是c++的new就要消耗很大一部分时间,我们知道比赛一般往往更倾向于时间复杂度更优的算法,很多的算法也都是基于此目的而衍生和创建出来的,今天我们就来学习如何利用数组在比赛中快速模拟实现链表的操作。

目录

1.数组实现的相关要求和原理 

1.1 链接关系和权值该怎么表示?

1.2链表的头结点和结束标志是什么?

1.3遍历方法

 1.4链表的相关操作的模拟实现举例

头插增加一个节点

尾插一个节点

删除pos位置的节点

在pos之前插入数据

2.相关的链表增删查改功能实现

 3.金句频道


1.数组实现的相关要求和原理 

       我们期望利用数组来帮助我们实现链表,链表的一些基本功能就一定要满足,比如单链表的增删查改操作等,下面我们就来用问题引出方法:

1.1 链接关系和权值该怎么表示?

       在结构体模式的链表中,我们通过next指针来实现链表的”链接“功能,而在数组中,我们可以尝试建立两个数组,用来分别存储点的权值和该点的下一个节点,我们这里以e[i]和ne[i]来命名,我们可以在e[i]中保存我们点对应的权值,而在ne[i]总存储i节点的下一个节点,为了方便,我们以数组的下标来唯一标识节点位置,注意我们的下标表示的是该节点插入链表的顺序,这样我们就可以在ne[i]中保存数组的下标,从而达到链接的目的。

        节点插入链表的顺序,这里我们需要指明,假设第三个节点插入,那么假设该节点的下标为3,此后3下标对应的点被删掉了,那么链表中就不存在下标为3的节点了,也就是说3这个不再使用了,我们下标的使用规则是一直增大,不会减小。

1.2链表的头结点和结束标志是什么?

       初始时,我们可以创建一个head变量,并将其赋值为-1,可能有人会问这里的结束标志如何才能不与节点的数据域的数据冲突,其一,我们的head表示的是头结点所对应的下标,和数据域并没有直接联系,其二,数组的下标是不可能为负数的,所以我们的结束判断条件可以使用。

1.3遍历方法

       我们通过头结点指向的下标开始,每次输出该下标对应的权值,然后将下标改为上一个下标对应的节点所表示的下一个节点的下标,继续遍历,重复此过程,直到某一次节点的下一个节点的下标为-1,即为遍历结束。

void print()
{
	int i = head;
	while (1)
	{
		printf("%d ", e[i]);
		i = ne[i];
		if (i == -1)
			break;
	}
	printf("\n");
}

下面,我们就尝试画出结构图来帮助理解:

 1.4链表的相关操作的模拟实现举例

头插增加一个节点

void add_front(int x)//在链表头插入一个元素
{
	e[idx] = x;//保存权值
	ne[idx] = head;
	head = idx;
	idx++;
}

尾插一个节点

void add_back(int x)
{
	e[idx] = x;
	int i = head;
	while (ne[i] != -1) //找到最后一个节点
	{
		i = ne[i];
	}
	ne[i] = idx;
	ne[idx] = -1;
	idx++; 
}

删除pos位置的节点

//删除pos位置处的数据
void remove_pos(int pos)
{
	int i = head;
	while (ne[i] != pos)
		i = ne[i];
	ne[i] = ne[ne[i]];
}

在pos之前插入数据

这里的pos表示下标,如果idx初始化为0,则pos可以等于0,否则pos需大于0

void add_insert_front(int pos,int x)
{
	if (pos == 0)
		add_to_head(x);
	else 
	{
		//目前我只想到了从前往后遍历才能找到pos之前的节点,所以各位大佬有何高明见解欢迎指出
		int i = head;
		while (ne[i] != pos)
		{
			i = ne[i];
		}
		e[idx] = x;
		ne[i] = idx;
		ne[idx] = pos;
		idx++;
	}
}

2.相关的链表增删查改功能实现

代码为理想情况下的实现,有欠考虑的非法样例,如果读者发现错误,还请指出,您指出的BUG对你对我都是提升,何乐而不为呢?

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int e[maxn], ne[maxn], idx, head;//e表示点的权值,ne表示节点的下一个节点所代表的下标,idx表示当前可以插入的点的下标位置,head表示头结点,初始指向-1表示为空
//初始化
void init()
{
	head = -1;//初始时head指向-1
	idx = 1;//idx可以为1也可以为0,区别只是开始存的下标不一致
}

//在头部插入数据
void add_to_head(int x)
{
	e[idx] = x;
	ne[idx] = head;//将新的节点的下一个节点改为头结点
	head = idx;//头结点更新为新插入的节点
	idx++;//下一个待插入的位置
}

//销毁链表
void destory()
{
	ne[head] = -1;//直接将头结点的下一个节点更新为-1即可,数组中存在的值不用销毁

}

//在尾部插入数据
void add_to_back(int x)
{
	//先找到最后一个节点
	int i = 0;
	for (i = head; ne[i] != -1; i = ne[i]);

	//插入即可,此时i就是最后一个节点的下标
	e[idx] = x;
	ne[i] = idx;
	ne[idx] = -1;
	idx++;
}

//查找指定数据
void find_x(int x)
{
	for (int i = head; i != -1; i = ne[i])
	{
		if (e[i] == x)
		{
			printf("查找成功\n,第一个%d存储在下标为%d的位置处\n", x, i);
			return;
		}
	}
	printf("查无此节点\n");
	return;
}

//在pos之前插入数据,这里的pos表示下标,如果idx初始化为0,则pos可以等于0,否则pos需大于0
void add_insert_front(int pos,int x)
{
	if (pos == 0)
		add_to_head(x);
	else 
	{
		//目前我只想到了从前往后遍历才能找到pos之前的节点,所以各位大佬有何高明见解欢迎指出
		int i = head;
		while (ne[i] != pos)
		{
			i = ne[i];
		}
		e[idx] = x;
		ne[i] = idx;
		ne[idx] = pos;
		idx++;
	}
}

//在pos之后插入数据
void add_insert_back(int pos, int x)
{
	
	if (ne[pos] == -1)//最后一个节点后面插入相当于后插,但是后面的也是可以使用的,这里if...else可以合并
		add_to_back(x);
	else
	{
		e[idx] = x;
		ne[idx] = ne[pos];
		ne[pos] = idx;
		idx++;
	}
}

//打印链表
void print()
{
	int i = 0;
	for (i = head; ne[i] != -1; i = ne[i])
	{
		printf("%d->", e[i]);
	}
	printf("%d\n", e[i]);
}

//在头部删除数据
void front_remove()
{
	if (ne[head] == -1)//表示没有数据
	{
		printf("没有数据\n");
		return;
	}
	else
	{
		head = ne[head];//头结点指向所指向节点的下一个节点
	}
}

//在尾部删除数据
void back_remove()
{
	int i = head;
	if (head == -1)
	{
		printf("链表没有数据\n");
		return;
	}
	else 
	{
		while (ne[ne[i]] != -1)
			i = ne[i];
		ne[i] = -1;
		return;
	}
}


//删除pos位置处的数据
void remove_pos(int pos)
{
	int i = head;
	while (ne[i] != pos)
		i = ne[i];
	ne[i] = ne[ne[i]];
}

//删除pos位置后的数据
void remove_back_pos(int pos)
{
	if (ne[pos] == -1)
	{
		printf("该元素为最后一个,无法再删除后面的元素\n");
		return;
	}
	else 
	{
		ne[pos] = ne[ne[pos]];
	}
}

//修改pos位置处的函数
void modify_pos(int pos,int x)
{
	e[pos] = x;
}


//测试代码
int main()
{
	init();
	add_to_head(1);
	add_to_head(2);
	add_to_back(3);
	add_to_back(4);
	print();
	find_x(3);
	add_insert_front(3, 5);
	add_insert_back(3, 6);
	print();
	front_remove();
	back_remove();
	print();
	remove_pos(3);
	print();
	remove_back_pos(4);
	print();
	modify_pos(5, 6);
	print();
	return 0;
}

 3.金句频道

       这个模块已经开设很久了,不知道这些言语能不能直击你的灵魂,我只是希望,我们年轻一代不要堕落下去,疫情已经过去,我们不该再有借口不努力了。

      真正的人脉关系是靠自己吸引过来的。你本身有价值的话,就会有很多的人想要跟你交朋友。不要沉迷于无用社交,而忽视了自己的个人成长。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

找出1-1000中的所有完美数

再次练习查找完美数&#xff0c;找出 1-1000 中的所有完美数。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简单…… 地址&#xff1a;https://l…

Git的安装和学习使用(一)

本篇文章旨在分享本人在学习Git时的随笔记&#x1f929; 文章目录 一、Git 快速入门1.1 Git 概述1.2 SCM概述1.3 Git 安装1.3.1 软件下载1.3.2 软件安装1.3.3 软件测试 二、Git 基础使用2.1 Git 概念2.1.1 版本控制2.1.2 分布式2.1.3 系统2.1.4 区域 2.2 Git 基础指令2.2.1 Lin…

任务调度原理 通俗讲解详细(FreeRTOS)

寄存器说明 以cortex-M3&#xff0c;首先先要了解比较特别的几个寄存器&#xff1a; r15 PC程序计数器&#xff08;Program Counter&#xff09;,存储下一条要执行的指令的地址。 r14 LR连接寄存器&#xff08;Link Register &#xff09;&#xff0c;保存函数返回地址&#x…

Rancher 部署 Elasticsearch 8.5.1 版本服务

前言 从 es7 升级到 es8 之后&#xff0c;启动容器默认启用了 ssl 安全传输配置&#xff0c;但是在 Rancher 中部署的话&#xff0c;需要挂载 pvc 实现 data、logs 等目录持久化&#xff0c;启用 ssl 需要对证书等进行操作&#xff0c;非常麻烦&#xff0c;非常坑。 本文以启…

bitset(位图)的使用与模拟实现

bitset&#xff08;位图&#xff09; 位图引入bitset的使用bitset&#xff08;位图&#xff09;的模拟实现bitset类各函数接口总览bitset类的实现构造函数set、reset、flip、testsize、countany、none、all打印函数 位图引入 问&#xff1a;给40亿个不重复的无符号整数&#xf…

AlgoC++第三课:C++世界观

目录 C世界观前言1. 程序逻辑2. 内存的逻辑3. 调度的逻辑4. 编译的逻辑5. 作用域的逻辑6. 命名空间的逻辑7. 生命周期的逻辑8. C类的逻辑9. 编译时和运行时的逻辑总结 C世界观 前言 手写AI推出的全新面向AI算法的C课程 Algo C&#xff0c;链接。记录下个人学习笔记&#xff0c…

Vue+Vant封装通用模态框单选框组件

前言 我们知道&#xff0c;在vant组件中提供的组件往往是比较基础的&#xff0c;能够满足基本需求。但是我们想实现ui设计的一些比较丰富效果的组件&#xff0c;需要自己去实现&#xff0c;且当项目中多次用到的时候&#xff0c;我们将以组件化的思想将其封装起来&#xff0c;…

Linux服务器出现503 服务不可用错误怎么办?

​  HTTP 503 服务不可用错误代码表示网站暂时不可用。无论您是网站访问者还是管理员&#xff0c;503 页面都很麻烦。尽管该错误表明存在服务器端问题&#xff0c;但对于访问者和网络管理员来说&#xff0c;有一些可能的解决方案。本文将解释Linux服务器出现503 服务不可用错…

scratch足球射门练习 中国电子学会图形化编程 少儿编程 scratch编程等级考试一级真题和答案解析2023年3月

目录 scratch足球射门练习 一、题目要求 1、准备工作 2、功能实现 二、案例分析

【网络安全】红队基础免杀

引言 本文主要介绍“反射型 dll 注入”及“柔性加载”技术。 反射型 dll 注入 为什么需要反射型 dll 注入 常规的 dll 注入代码如下&#xff1a; int main(int argc, char *argv[]) {HANDLE processHandle;PVOID remoteBuffer;wchar_t dllPath[] TEXT("C:\\experime…

分享几个国内免费的ChatGPT镜像网址(亲测有效-4月25日更新)

最近由于ChatGPT的爆火也让很多小伙伴想去感受一下ChatGPT的魅力&#xff0c;那么今天就分享几个ChatGPT国内的镜像网址&#xff0c;大家可以直接使用&#xff01;记得点赞收藏一下呦&#xff01; 1、AQ Bot&#xff0c;网址&#xff1a;点我 https://su.askaiw.com/aq 缺点&…

面试篇:Redis

一、缓存穿透 1、缓存穿透 查询一个不存在的数据&#xff0c;mysql查询不到数据也不会直接写入缓存&#xff0c;就会导致每次请求都查数据库。即&#xff1a;大量请求根本不存在的key 2、查询流程 3、出现原因 业务层误将缓存和库中的数据删除了&#xff0c;也可能是有人恶…

JUC-多线程(12. AQS-周阳)学习笔记

文章目录 1. 可重入锁1.1. 概述1.2. 可重入锁类型1.3. Synchronized 可重入实现机理 2. LockSupport2.1. LockSupport 是什么2.2. 3种线程等待唤醒的方法2.2.1 Object 的等待与唤醒2.2.2. Condition接口中的等待与唤醒2.2.3. 传统的 synchronized 和 Lock 实现等待唤醒通知的约…

【手把手做ROS2机器人系统开发一】开发环境搭建

【手把手做ROS2机器人系统开发一】开发环境搭建 目录 【手把手做ROS2机器人系统开发一】开发环境搭建 一、专栏介绍&#xff1a; 二、开发环境搭建&#xff1a; 1.Ubuntu系统安装 2.ROS2系统环境安装 3.测试系统运行 一、专栏介绍&#xff1a; 大家好&#xff0c;今天给大家…

栈的基本操作(C语言实现)创建,销毁,入栈,出栈

前言 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#xff1a;栈的…

同样是测试,朋友到了30k,我才12K,这份测试面试8股文确实牛

程序猿在世人眼里已经成为高薪、为人忠诚的代名词。 然而&#xff0c;小编要说的是&#xff0c;不是所有的程序员工资都是一样的。 世人所不知的是同为程序猿&#xff0c;薪资的差别还是很大的。 众所周知&#xff0c;目前互联网行业是众多行业中薪资待遇最好的&#xff0c;…

Fedora 38 正式发布

Fedora Linux 38 正式发布&#xff0c;用户可以访问官网下载安装最新版本。 新网站 如果你点击了上面的官网链接&#xff0c;你应该会注意到 Fedora 的官网看起来与之前有了很大不同。这是 Fedora Websites & Apps 团队与 Design & Infrastructure 团队以及广大社区合作…

【视频课程】算法工程师需要的ChatGPT大模型算法理论与实践课程!非粗浅科普...

前言 自从2022年11月ChatGPT发布之后&#xff0c;迅速火遍全球。其对话的交互方式&#xff0c;能够回答问题&#xff0c;承认错误&#xff0c;拒绝不适当的请求&#xff0c;高质量的回答&#xff0c;极度贴近人的思维的交流方式&#xff0c;让大家直呼上瘾&#xff0c;更是带火…

安装配置SVN版本控制管理工具

SVN工具能帮我们做什么&#xff1f; 核心功能&#xff1a;文档版本管理系统 适合对象&#xff1a;个人与团队都可以使用&#xff0c;企业中项目资源的重要管理工具 举例&#xff1a;一个文件夹里面的文档管理 1.下载安装SVN服务器 VisualSVN-Server 2.下载安装SVN客户端 T…

<网络编程>网络套接字

目录 理解源IP地址和目的IP地址 认识端口号 端口号和进程ID的关系 理解源端口号和目的端口号 初步认识TCP、UDP协议 TCP协议 UDP协议 网络字节序列 socket网络接口 socket常见API sockaddr结构 UDPsocket 编码&#xff1a; 理解源IP地址和目的IP地址 源IP&#xf…