一文详解动态链表和静态链表的区别
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年前访华的老照片,残雪的获奖氛围在国内各类媒体的渲染下被拉至极高。当奖项…...
智慧公厕:将科技融入日常生活的创新之举
智慧公厕是当今社会中一项备受关注的创新项目。通过将科技融入公厕设计和管理中,这些公厕不仅能够提供更便利、更卫生的使用体验,还能够极大地提升城市形象和居民生活质量。本文将以智慧公厕领先厂家广州中期科技有限公司,大量的精品案例项目…...
ROS(0)命令及学习资源汇总
ROS安装命令 参考:Ubuntu20.04.4安装ROS Noetic详细教程 - 知乎 安装C和Python3 sudo apt-get install g sudo apt-get install python3 ROS运行小海龟仿真器 roscore确定ROS是否运行成功rosrun turtlesim turtlesim_node运行小海龟仿真器rosrun turtlesim turtle_…...
NodeMCU ESP8266开发流程详解(图文并茂)
文章目录 整体架构打开软件setuploop 连接开发板CP2102版本CH340版本 下载结论 整体架构 NodeMCU ESP8266基于Arduino IDE的开发相对来说还是比较容易上手的,我们基本需要以下几个东西; 一台安装好Arduino IDE的PC,并且已经部署环境&#x…...
【最终版】tkinter+matplotlib实现一个强大的绘图系统
文章目录 辅助坐标轴功能实现代码优化源代码 Python绘图系统: 前置源码: Python打造动态绘图系统📈一 三维绘图系统 📈二 多图绘制系统📈三 坐 标 轴 定 制📈四 定制绘图风格 📈五 数据生成导入…...
Postman使用实例
Postman使用实例 实体类Emp package com.example.springboot_postman.pojo;import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import javax.persistence.*; import j…...
【ES的优势和原理及分布式开发的好处与坏处】
文章目录 ES的优势及分布式开发的好处1.ES的优势1.1 优势概述1.2 相关问题1)为什么需要 Elasticsearch?MySQL 不行吗?2)SQL检索的问题:3)ES检索快的原理 2.分布式开发的好处与坏处 ES的优势及分布式开发的好…...
Autosar诊断实战系列23-CanTp半/全双工及相关工程问题思考
本文框架 前言1. CanTp半/全双工基本介绍1.1 差异比较1.2 不同模式下可能发生场景分析1.2.1 当CanTp正在发送1.2.2 当CanTp正在接收2. 相关工程问题思考前言 在本系列笔者将结合工作中对诊断实战部分的应用经验进一步介绍常用UDS服务的进一步探讨及开发中注意事项, Dem/Dcm/C…...
【Pandas】数据分组groupby
本文目标: 应用groupby 进行分组对分组数据进行聚合,转换和过滤应用自定义函数处理分组之后的数据 文章目录 1. 数据聚合1.1 单变量分组聚合1.2 Pandas内置聚合方法1.3 聚合方法使用Numpy的聚合方法自定义方法同时计算多种特征向agg/aggregate传入字典 2. 数据转换…...
【图像处理GIU】图像分割(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Java中的锁与锁优化技术
文章目录 自旋锁与自适应自旋锁消除锁粗化轻量级锁偏向锁重量级锁 自旋锁与自适应自旋 自旋锁是一种锁的实现机制,其核心思想是当一个线程尝试获取锁时,如果锁已经被其他线程持有,那么这个线程会在一个循环中不断地检查锁是否被释放…...
布局与打包
属性栏直接输入值,比代码更直观方便。 打包:...
做点效果图赚钱的网站/写文章免费的软件
input()、raw_input()都可以输入提示语 sys.stdin.readline()不能输入提示语 raw_input()可输入任何字符,enter后, 之前输入的任何字符包括空白符都被读取转换成字符串,但不会读取enter产生的换行符‘\n’ input()只能输入 “数字或者已经赋值…...
柏乡企业做网站/广告网络推广怎么做
ls常用参数详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。 玩Linux的老司机们每天都要敲的命令,但是这个鸡蛋的命令还有很多中玩法哟~跟着我一起敲一遍吧!在这里我就列举几个常用的选项…...
网页设计素材的制作与收集/山东自助seo建站
百花图谱 学园艺的应该收藏一份 转载于:https://blog.51cto.com/19851030/396586...
网站优化要素/软文通
1.cat 1.1 查看日志前n行 cat 文件名 | head -n 数量 cat info.log | head -n 200 # 查看info.log前200行 1.2 查看日志尾n行 cat 文件名 | tail -n 数量 cat info.log | tail -n 200 # 查看info.log后200行 1.3 根据关键词查看日志,并返回关键词所在行 1.3…...
网站模板设计举例/深圳大鹏新区葵涌街道
文章目录前言一、Tomcat服务器1.核心组件①web容器:② servlet容器:③JSP容器(JAVA Scripts page):2.Tomcat 处理请求过程二、Tomcat部署1.安装JDK,配置JAVA环境2.安装配置Tomcat3.主要目录说明三、Tomcat优化1.优化启动速度2.常用的优化相关参数如下:四…...
东莞网站制作网站设计/中国网站排名网
实例化出来的调用,叫做方法 直接用类名的调用,叫做函数 1 #例如2 class Car:3 def __init__(self,c):4 self.color c5 def setSpeed(self,s):6 self.speed s7 8 car1 Car()9 car1.setSpeed(50)#这是一个方法 10 C…...