算法模版:模拟数据结构之链表

简介: 算法模版:模拟数据结构之链表

前言


唤我沈七就好。

本专题的绪论部分里已经简单的解释了什么是数据结构,以及有哪些常见的数据结构。

准备工作完毕之后。

接下来我们就开始进入本板块的正文部分,

模拟数据结构之链表

还是那句话。

蒟蒻因为实在是太弱了,肯定免不了错误百出。

欢迎批评指正,期待共同成长!

什么是链表?


回答这个问题,就不得不提一下链表的孪生兄弟—数组了,其实这两者都属于同一种数据结构—线性表。

但因为存储结构的不同而被划分成了两类。

数组是顺序存储结构,而链表则是链式存储。

关于数组想必各位都已经很熟悉了,所以这次主要讲解模拟链表部分。

在此之前先来谈谈数组在使用时存在的问题。

想必最令人头痛的应该就是数组在插入和删除时需要移动大量元素,这显然是非常耗费时间的。

而链表的出现则很好的解决了这个问题。

链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。

这就意味着,这些数据元素可以存在内存未被占用的任意位置(如图3-6-1所示)。

5.png



实现思路


为什么当插入和删除时,就要移动大量元素,仔细分析后,发现原因就在于相邻两元素的存储位置也具有邻居关系。

它们编号是1,2,3,…,n,它们在内存中的位置也是挨着的,中间没有空隙,当然就无法快速介入,而删除后,当中就会留出空隙,自然需要弥补。问题就出在这里。


那如何解决呢?


我们反正也是要让相邻元素间留有足够余地,那干脆所有的元素都不要考虑相邻位置了。

哪有空位就到哪里,只是让每个元素知道它下一个元素的位置在哪里。这样,我们可以在第一个元素时,就知道第二个元素的位置(内存地址),而找到它;

在第二个元素时,再找到第三个元素的位置(内存地址)。这样所有的元素我们就都可以通过遍历而找到。


这思路是不是很妙,难点就是如何实现让每一个元素知道它下一个元素的位置在哪里。

而我们恰巧有一个现成的东西----指针。

但考虑到用指针操作略显复杂,

所以我们这里用下标来作为地址,用一个新数组来代替指针储存下标。

我们将两个数组用下标来对应起来也可以达到指针的效果,

只需要用一个数组用来存储数据,新数组在同下标位置记录下一个元素所在的下标,

这样用数组描述的链表也被称为静态链表。


注意:下文为了方便描述,我将记录下一个结点地址(下标)的变量都统称为了指针


一些术语


结点:链表上的某个数据元素我们称为结点。

头指针:链表中第一个结点的存储位置叫做头指针。整个链表的存取必须从头指针开始进行。


实现方法


1 .创建变量


const int N=1e6+10; 
 int e[N];    存储结点的值。
 int ne[N];   存储结点的指针(即下一个结点的下标)。
 int head;    存储链表头,即头指针。
 int idx;     表示当前用到了哪个结点。


关于 head

刚开始的时候它负责指向空结点,在链表里有元素的时候,它变成了一个指向第一个元素的指针。


2 .初始操作

初始化
head=-1;    表示链表没有内容。
idx=0;      链表中还没有元素,故从零开始。


最开始的时候,链表的头节点要指向-1,

为的就是在后面进行不断操作后仍然可以知道链表是在什么时候结束。

虽然我们在进行各种操作的时候,元素所在的下标看上去很乱,

但是当我们访问的时候,是靠着指针,也就是靠ne[ ]来访问的,

这样即便下标乱,也与我们要做的事不相关了。

另外,我们遍历链表的时候也是这样,靠的是ne[ ]。


3 .插入操作


链表的插入有两种分别是①头结点插入和②链表中间插入。


①头结点插入。


void int_to_head(int x){//和链表中间插入的区别就在于它有head头节点
    e[idx] = x;       第一步,先将值放进去
    ne[idx] = head;   head作为一个指针指向空节点,现在ne[idx] = head;做这把交椅的人换了
                      先在只是做到了第一步,将元素x的指针指向了head原本指向的
    head = idx;       head现在表示指向第一个元素了,它不在是空指针了。(不指向空气了)
    idx ++;           结点向下移一位,为下一次插入元素做准备。
}


②将x插入到下标为k的点的后面。


void add(int k, int x){
    e[idx] = x;         先将元素插进去
    ne[idx] = ne[k];    让元素x配套的指针,指向它要占位的元素的下一个位置
    ne[k] = idx;        让原来元素的指针指向自己
    idx ++; }           将idx向后挪


所采用的思路就是


将x的指针指向 k 指针指向的结点,也就是 k 的下一个结点。

即 ne[idx] = ne[k]; 现在x的后面就是曾经是 k 后面的结点了。


然后改变k的指针,将其指向指向x

即 ne[k] = idx; 现在 k的后面就是x了。


4 .删除操作


将下标是k的后一个结点删掉


void remove(int k){
    ne[k] = ne[ne[k]];  让k的指针指向,k下一个人的下一个人,那中间的那位就被挤掉了。
}


实现删除操作的思路也很妙.

其实我们没必要真的删除储存在e[ ]的数据,而是需要对ne[ ]下文章。

只需要将ne[ ]下标为 k 的指针指向原本指向的结点的下一个就可以了。

这种 k 原本的下一个结点就被越过去, k 直接指向了下下个,而遍历是靠指针ne[ ]来做的,所以k 的下一个结点永远不会被遍历到,这样就达到了删除的效果。


5 .链表遍历


for(int i=head;i!=-1;i=ne[i])
cout<<e[i];


通过指针数组ne[ ]来遍历,应该最开始head指向的 -1 。

经过数据不断的插入,-1 仍然是最后一个结点(此节点不存贮具体数据,仅用于链表遍历)。

所以只要指针不等于 -1 就说明链表还没遍历完。


算法模板


const int N=1e6+10;
int head, e[N], ne[N], idx;
// 初始化
void init()  
{ head = -1;  idx = 0;}
// 在链表头插入一个数a
void head_add(int a)
{
    e[idx] = a,ne[idx] = head, head = idx ++ ;
}
//在k的后面插入x(k!=0)
void add(int k, int x)
{
    e[idx] = x;//先将元素插进去
    ne[idx] = ne[k];//让元素x配套的指针,指向它要占位的元素的下一个位置
    ne[k] = idx;//让原来元素的指针指向自己
    idx ++;//将idx向后挪
}
//将其他节点删除(k!=0)
void Delete(int k)
{
  n[k]=ne[ne[k]];
}
//链表遍历
for(int i=head;i!=;i=ne[i])
cout<<e[i];


完结散花


ok以上就是对模拟数据结构之链表的全部讲解啦,很感谢你能看到这儿啦。如果有遗漏、错误或者有更加通俗易懂的讲解,欢迎小伙伴私信我,我后期再补充完善。


参考文章


[1]程杰.大话数据结构[M].北京:清华大学出版社 ,2011:5-14 .


https://www.acwing.com/solution/content/16251/


全部模板链接


https://www.acwing.com/blog/content/404


相关文章
|
2月前
|
存储 监控 算法
基于 Go 语言跳表结构的局域网控制桌面软件进程管理算法研究
针对企业局域网控制桌面软件对海量进程实时监控的需求,本文提出基于跳表的高效管理方案。通过多级索引实现O(log n)的查询、插入与删除性能,结合Go语言实现并发安全的跳表结构,显著提升进程状态处理效率,适用于千级进程的毫秒级响应场景。
169 15
|
2月前
|
分布式计算 并行计算 算法
《数据之美》:图结构的精妙世界与算法实践
图是表示多对多关系的非线性数据结构,由顶点和边组成,可建模社交网络、路径导航等复杂系统。核心算法包括BFS/DFS遍历、Dijkstra最短路径、Floyd-Warshall全源最短路径,以及Prim和Kruskal最小生成树算法,广泛应用于推荐系统、社交分析与路径规划。
|
3月前
|
运维 监控 JavaScript
基于 Node.js 图结构的局域网设备拓扑分析算法在局域网内监控软件中的应用研究
本文探讨图结构在局域网监控系统中的应用,通过Node.js实现设备拓扑建模、路径分析与故障定位,提升网络可视化、可追溯性与运维效率,结合模拟实验验证其高效性与准确性。
265 3
|
3月前
|
存储 监控 算法
企业电脑监控系统中基于 Go 语言的跳表结构设备数据索引算法研究
本文介绍基于Go语言的跳表算法在企业电脑监控系统中的应用,通过多层索引结构将数据查询、插入、删除操作优化至O(log n),显著提升海量设备数据管理效率,解决传统链表查询延迟问题,实现高效设备状态定位与异常筛选。
142 3
|
存储 算法 Perl
数据结构实验之链表
本实验旨在掌握线性表中元素的前驱、后续概念及链表的建立、插入、删除等算法,并分析时间复杂度,理解链表特点。实验内容包括循环链表应用(约瑟夫回环问题)、删除单链表中重复节点及双向循环链表的设计与实现。通过编程实践,加深对链表数据结构的理解和应用能力。
232 4
|
10月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
405 30
|
8月前
|
存储 算法 物联网
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
161 0
|
10月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
506 25
|
11月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
558 5
|
12月前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充

热门文章

最新文章