一文详解动态链表和静态链表的区别
1、引言
本文主要是对动态链表和静态链表的区别进行原理上的讲解分析,先通过对顺序表和动态链表概念和特点的原理性介绍,进而引申出静态链表的作用,以及其概念。通过这些原理性的概述,最后总结归纳出动态链表和静态链表的区别。本文不对代码进行额外的讲解,只对原理进行分析以加深基础的认识,相关概念的代码应用读者可以另行在网上进行搜索详细学习。
2、顺序表和动态链表的特点
首先需要明白的是,顺序表和链表都是线性表,即线性存储结构。使用线性表存储数据的方式可以这样理解,即“把所有数据用一根线串起来,再存储到物理空间中”。
如下图左边将数据依次存储在连续的整块物理空间中,这种存储结构称为顺序存储结构(简称顺序表);下图右边数据分散的存储在物理空间中,通过一根线保存着它们之间的逻辑关系,这种存储结构称为链式存储结构(简称链表)。可以看出每一个数据按照“一对一”的关系按照次序逐个排列。

2.1 顺序表存储结构
顺序表对数据的物理存储结构有要求,需预先申请一整块足够大的存储空间,然后将数据依次存储起来,数据之间紧密贴合,不留一丝空隙。如下图所示,顺序表数据的 '一对一' 逻辑关系就是数据按照次序连续存储到一整块物理空间上,一个数据存储在一个位置之后紧接着就是下一个数据存储在下一个连续的位置。其数据存储方式和数组非常相似。

使用顺序表存储数据之前,除了要申请足够大小的物理空间之外,为了方便后期使用表中的数据,顺序表还需要实时记录以下 2 项数据:(1)顺序表申请的存储容量,即总的空间大小,类似于数组的总大小;(2)顺序表的长度,也就是当前表中存储数据元素的个数。正常状态下,顺序表申请的存储容量要大于顺序表的长度。顺序表的结构表示如下:
typedef struct Table
{int * head;//声明了一个名为head的长度不确定的数组,也叫“动态数组”int length;//记录当前顺序表的长度int size;//记录顺序表分配的存储容量
}table;
2.2 链表存储结构
链表的存储方式与顺序表截然相反,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据元素,其物理存储位置不是连续的,而是随机的。什么时候存储数据,才在什么时候申请存储空间。链表数据的 '一对一' 逻辑关系就是数之间通过指针来维持,一个数据存储在一个位置之后通过指针指向下一个数据存储在下一个位置。这样的链表,也称之为"动态链表"。

链表中每个数据的存储都由两部分组成:(1)数据元素本身,其所在的区域称为数据域;(2)指向直接后继元素的指针,所在的区域称为指针域。这两个部分组成了链表中的一个数据节点,链表实际存储的是一个一个的节点,链表数据节点的结构表示如下:
typedef struct Link
{char elem; //代表数据域struct Link * next; //代表指针域,指向直接后继元素
}link; //link为节点名,每个节点都是一个 link 结构体
2.3 顺序表和动态链表的比较
根据以上介绍的顺序表和动态链表的存储结构特点,可以比较出两者在以下几个方面的区别:
(1)开辟空间的方式
顺序表存储数据实行的是 "一次开辟,永久使用",即存储数据之前先开辟好足够的存储空间,空间一旦开辟后期无法改变大小(使用动态数组malloc的情况除外)。
而动态链表则不同,动态链表存储数据时一次只开辟存储一个节点的物理空间,如果后期需要还可以再申请。
因此,若只从开辟空间方式的角度去考虑,当存储数据的个数无法提前确定,又或是物理空间使用紧张以致无法一次性申请到足够大小的空间时,使用动态链表更有助于问题的解决。
(2)空间利用率
顺序表的空间利用率高,而动态链表的空间利用率低。
顺序表用一段连续的存储单元依次存储线性表的数据元素,物理空间上是连续的;动态链表用一组任意的存储单元存放线性表的元素,逻辑上连续(通过指针维持),但物理空间上不一定连续。
动态链表在物理空间上不一定连续是由于每次只申请一个节点的空间,且空间的位置是随机的。这种申请存储空间的方式会产生很多空间碎片,一定程度上造成了空间浪费。不仅如此,由于动态链表中每个数据元素都必须携带至少一个指针,因此,动态链表对所申请空间的利用率没有顺序表高。
(3)插入元素的容量
顺序表中,空间不够时需要扩容,扩容会有一定的消耗,扩容后可能存在一定的空间浪费;动态链表没有容量的概念,按需申请空间。
(4)存储密度
顺序表中,其存储密度均为1,因为数组空间只用来存数据元素。而在动态链表中,每个节点除了存储数据元素自身外,还会至少存储直接后继的存储位置信息。相对于顺序表,动态链表的存储密度要低得多。
(5)时间复杂度
针对随机访问性能来说:
顺序表随机访问一个元素可以用下标的方式直接访问,无需遍历整个表,时间复杂度为O(1);动态链表随机访问一个元素,需要从头到尾遍历,直到寻找到该元素,时间复杂度为O(N)。
针对任意位置插入或者删除元素来说:
顺序表可能需要按顺序搬移大量元素后进行元素的插入或删除,效率较低,时间复杂度为O(N);动态链表中数据元素之间的逻辑关系靠的是节点之间的指针,因此在动态链表中插入或删除元素只需修改指针的指向,不需搬移大量元素,时间复杂度为O(1)。
因此涉及访问元素的操作,而元素的插入、删除和移动操作极少的场景时,适合用顺序表;涉及元素的插入、删除和移动,而访问元素的需求很少的场景时,适合用动态链表。
3、为什么会有静态链表
单站在时间复杂度的角度上来看,是否能够有一种数据结构既能够像顺序表一样快速的访问数据元素,又可以像动态链表一样可以方便的插入、删除和移动数据元素?
静态链表就是这样一种数据结构,其属于一种线性存储结构,分配一整片连续的内存空间,各个节点集中安置,逻辑结构上相邻的数据元素,存储在指定的一块内存空间中,数据元素只允许在这块内存空间中随机存放。数据全部存储在数组中(和顺序表一样),但存储位置是随机的,数据之间"一对一"的逻辑关系通过一个整型变量(称为"游标",和指针功能类似)维持(和链表类似)。在将数据存放到数组中时,给各个数据元素配备一个整形变量,此变量用于指明各个元素的直接后继元素所在数组中的位置下标。
如图中a[0]~a[6]为数组下标,分配的内存空间中绿色数字为数组的数据元素,红色数字就为数组的游标变量,表示当前节点的下一个节点的数组下标。因此下标为x的数组中存放当前的数组数据元素和后继元素所在数组中的位置下标。因此可以看出静态链表是用数组来实现链式存储结构,静态链表实际上就是一个结构体数组。

如上图:a[1]中存放的数据元素值为2,通过a[1]中存放的游标变量4可找到后继元素所在的数组a[4];a[4]中存放的数据元素值为5,通过a[4]中存放的游标变量3可找到后继元素所在的数组a[3];a[3]中存放的数据元素值为7,通过a[3]中存放的游标变量6可找到后继元素所在的数组a[6]。以此类推,直到某元素的游标变量为0即可停止(注意:a[0]为头结点,其不存储数据元素)。
但是从上图中,可以看出数组中间有未使用过的空间即没有数据元素的数组成员,这样岂不是浪费了存储空间?为了使我们创建的空间能够得到充分的利用,我们还需要一条连接各个空闲位置的链表,方便我们的随取随用,这条链表也被称为备用链表。
备用链表的作用是回收数组中未使用或之前使用过(目前未使用)的存储空间,留待后期使用。也就是说,静态链表使用数组申请的物理空间中,存有两个链表,实现不同的功能,一个用来连接数据,另一个用来连接数组中的空闲空间。

为了适应这个,会存在一个“潜规则”,默认备用链表的表头位于数组下标为0(a[0])的位置,而数据链表的表头位于数据下标为1(a[1])的位置。备用链表的数组成员中仅存放游标。如上图所示:备用链表的连接顺序依次是:a[0]、a[2]、a[5],数据链表的连接顺序依次是a[1]、a[3]、a[4]、a[6]。
静态链表中设置备用链表的好处是:可以清楚地知道数组中是否有空闲位置,以便数据链表添加新数据时使用。在静态链表的插入和删除操作中,都会与备用链表有着联系,当进行插入时,则是用备用链表上面取得一个节点作为待插入的新节点,反之,当在删除时,则将从链表上删除下来的节点链接到备用链表上面。整个过程中,我们需要做的工作就是更新游标的值。
可见静态链表由数据链表的数据链表的各个节点和的备用链表的各个节点组成,静态链表节点的结构表示如下:
typedef struct List
{int data;//数据域int cur;//游标
}list;
4、动态链表和静态链表的区别
通过以上对动态链表和静态链表原理概念和各自特点的介绍,我们可以对两者的区别有一个更深的认知。
(1)链表中数据“一对一”的关系
动态链表是靠指针来维持。
静态链表是靠游标来维持。
(2)内存空间申请
使用动态链表存储数据,不需要预先申请内存空间,而是在需要的时候才向内存申请。也就是说,动态链表存储数据元素的个数是不限的,想存多少就存多少。
使用静态链表存储数据,需要预先申请足够大的一整块内存空间,也就是说,静态链表存储数据元素的个数从其创建的那一刻就已经确定,后期无法更改。
(3)物理地址
动态链表malloc 或 free 函数动态申请或释放内存,在长度上没有限制。因为是动态申请内存的,所以每个节点的物理地址不连续
静态链表类是似于数组方法实现的,在物理地址上是连续的,而且需要预先分配地址空间大小,所以静态链表的初始长度一般是固定的。
(4)操作方式
使用动态链表只需操控一条存储数据的链表。当表中添加或删除数据元素时,只需要通过 malloc 或 free 函数来申请或释放空间。
静态链表是在固定大小的存储空间内随机存储各个数据元素,使用静态链表存储数据,需要操控两条链表,一条是存储数据的数据链表,另一条是记录空闲空间位置的备用链表,便于随时分配给新添加元素使用。当表中添加或删除数据元素时,需要更新数据链表和备用链表的对应节点的值。
(5)元素的访问
动态链表随机访问一个元素,需要从头到尾遍历,直到寻找到该元素,时间复杂度为O(N)。
静态链表随机访问一个元素,可以类似像数组通过下标的方式,通过游标来访问,时间复杂度为O(1)。
(6)元素的插入和删除
动态链表插入或删除元素时不用做元素的移动,修改指针域即可。
静态链表插入或删除元素时不用做元素的移动,可以通过修改游标的值来达到。
↓↓↓更多技术内容和书籍资料获取,入群技术交流敬请关注“明解嵌入式”↓↓↓
相关文章:
一文详解动态链表和静态链表的区别
1、引言 本文主要是对动态链表和静态链表的区别进行原理上的讲解分析,先通过对顺序表和动态链表概念和特点的原理性介绍,进而引申出静态链表的作用,以及其概念。通过这些原理性的概述,最后总结归纳出动态链表和静态链表的区别。本…...
[C国演义] 第十三章
第十三章 三数之和四数之和 三数之和 力扣链接 根据题目要求: 返回的数对应的下标各不相同三个数之和等于0不可包含重复的三元组 – – 即顺序是不做要求的 如: [-1 0 1] 和 [0, 1, -1] 是同一个三元组输出答案顺序不做要求 暴力解法: 排序 3个for循环 去重 — — N^3, …...
<二>Qt斗地主游戏开发:过场动画的实现
1. 过场动画效果 2. 思路分析 过场动画较为简单,只有一个进度条在进行滚动,因此实现起来不需要动画相关处理,仅需要图片和定时器设定,让进度条动起来即可。我们可以创建一个对话框,设定背景图片以及对话框透明无边框&a…...
链式法则(Chain Rule)
定义 链式法则(Chain Rule)是概率论和统计学中的一个基本原理,用于计算联合概率分布或条件概率分布的乘积。它可以用于分解一个复杂的概率分布为多个较简单的条件概率分布的乘积,从而简化概率分析问题。 链式法则有两种常见的形…...
AUTOSAR COM模块框架梳理
框架: COM的功能主要就是两个: 把IPDU内的signal提取出来提供给SWC使用,把SWC发送的signal拷贝到IPDU buffer内 所以,COM的关键字是 signal, signal group, IPDU, IPDU group Signal group 是为了保证 Complex Data Types 的数…...
详细介绍区块链之挖矿
对不起,大家,这篇文章对作者来说实在是太有意义和含金量了,作者想把它设置为关注博主才能见全文,请大家理解!如果觉得还是看不懂,抱歉耽误大家的时间,就请取消关注!!&…...
华为OD机试真题-路灯照明问题(Java/C++/Go/Python)
【华为OD机试真题】路灯照明问题(Java/C++/Go/Python) 题目描述 在一条笔直的公路上安装了N个路灯,从位置0开始安装,路灯之间间距固定为100米。 每个路灯都有自己的照明半径,请计算第一个路灯和最后一个路灯之间,无法照明的区间的长度和。 输入描述 第一行为一个数N…...
嵌入式技术面试基本规则
潜规则1:面试的本质不是考试,而是告诉面试官你会做什么 经验不够的小伙伴特别容易犯的一个错误,不清楚面试官到底想问什么,其实整个面试中面试官并没有想难倒你的意思,只是想通过提问的方式来知道你会什么。 比如stm…...
osg实现自定义插件读取自定义格式的模型文件到场景
目录 1. 前言 2. 预备知识 3. 工具、原料 4. 代码实现 1. 前言 osg提供了很多插件来读取模型文件到场景中,这些插件支持大约70种格式类型的文件,但现实中的文件是各式各样,osg不可能囊括所有类型文件,当osg不支持某种类型格式…...
redis进阶
redis.conf 启动的时候就通过配置文件来启动的! # 这个不是配置的,就是在这儿说明一下 # 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写) # # 1k > 1000 bytes # 1kb > 102…...
(一)正点原子STM32MP135移植——准备
一、简述 使用板卡:正点原子的ATK-DLMP135 V1.2 从i.mx6ull学习完过来,想继续学习一下移植uboot和内核的,但是原子官方没有MP135的移植教程,STM32MP157的移植教程用的又是老版本的代码,ST官方更新后的代码不兼容老版本…...
Kotlin的关键字 lateinit 和 lazy
序、完善一下曾经的草稿。 Kotlin通常要求我们在定义属性后立即对起进行初始化,当我们不知道理想的初始值时,这样做似乎很奇怪,尤其是在生命周期驱动android属性的情况下。 lateinit 简介 lateinit,Kotlin提供的一个可以延迟初…...
阿里云服务器ECS详细介绍_云主机_服务器托管_弹性计算
阿里云服务器ECS英文全程Elastic Compute Service,云服务器ECS是一种安全可靠、弹性可伸缩的云计算服务,阿里云提供多种云服务器ECS实例规格,如经济型e实例、通用算力型u1、ECS计算型c7、通用型g7、GPU实例等,阿里云服务器网分享阿…...
12、建立健全人员培训体系
9、大小屏分离与精细化审核 10、质量审核的设立与合并 11、视频分类建议 内容仓为公司其他部门输送了许多人才,既包括有潜力的主管,也有表现突出或者具备某些特殊能力的员工,从内容仓走出的同事,有些已经成为公司重要业务某个方…...
代码随想录算法训练营第五十九天 | 647. 回文子串 516.最长回文子序列
1. 回文子串 647. 回文子串 - 力扣(LeetCode) 一个子串左右两个元素相等,并且中间对称,才是回文子串 即 ij 时,[i1: j-1]对称 dp[i][j]: [i:j] 是否是回文字串 当 子串长度大于2 由 dp[i1][j-1] 推出…...
React Redux
redux是什么 Redux是一个模式和库,用于管理和更新应用程序状态,使用称为“action”的事件。它是需要在整个应用程序中使用的状态的集中存储,规则确保状态只能以可预测的方式更新。 Redux主要有三个功能: 获取当前状态更新状态监…...
StreamingLLM - 处理无限长度的输入
文章目录 关于 StreamingLLM使用关于 StreamingLLM Efficient Streaming Language Models with Attention Sinks GitHub : https://github.com/mit-han-lab/streaming-llm论文:https://arxiv.org/abs/2309.17453在流媒体应用程序(如多轮对话)中 部署大型语言模型(LLM)是迫…...
[Linux 命令] nm 详解
1. nm 命令: 显示关于指定 File 中符号的信息,文件可以是对象文件、可执行文件或对象文件库。如果文件没有包含符号信息,nm 命令报告该情况,但不把它解释为出错条件。 nm 命令缺省情况下报告十进制符号表示法下的数字值。 2. 命…...
好文学作品的鉴赏标准
好文学作品的鉴赏标准 2023年诺贝尔文学奖颁给了挪威剧作家约恩福瑟。由于之前的博彩公司给中国作家残雪开出了最高的赔率,以及诺贝尔官方推特在揭晓奖项前发布了一张泰戈尔99年前访华的老照片,残雪的获奖氛围在国内各类媒体的渲染下被拉至极高。当奖项…...
智慧公厕:将科技融入日常生活的创新之举
智慧公厕是当今社会中一项备受关注的创新项目。通过将科技融入公厕设计和管理中,这些公厕不仅能够提供更便利、更卫生的使用体验,还能够极大地提升城市形象和居民生活质量。本文将以智慧公厕领先厂家广州中期科技有限公司,大量的精品案例项目…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
