深入理解数据结构:链表
文章目录
- 🌰导语
- 🌰链表的定义及基本结构
- 🌰单链表
- 🥕单链表特点
- 🌰双向链表
- 🥕双链表特点
- 🌰循环链表
- 🥕循环链表特点
- 🌰链表的操作
- 🍆链表的插入
- 🫘链头插入
- 🫘链间插入
- 🍆链表的删除
- 🫘链头删除
- 🫘链间删除
- 🍆链表的查询
- 🌰链表的应用场景
- 🌰链表与数组的比较
- 🌳存储方式
- 🌳插入和删除操作
- 🌳访问效率
- 🌳空间效率
- 🌰结语
🌰导语
链表是一种常用的数据结构,通过节点之间的指针连接而成,具有动态性和高效的插入删除操作。本文将深入介绍链表的定义、类型、操作以及应用场景,帮助读者全面理解链表的原理和使用。
🌰链表的定义及基本结构
链表是一种由节点组成的数据结构,每个节点包含存储数据的部分以及指向下一个节点的指针。通过节点之间的指针连接,形成了链表的结构。链表可以分为单链表、双向链表和循环链表等不同类型,它们各自具有特定的特点和应用场景。
- 数据元素:节点存储的实际数据。数据可以是任意类型,例如整数、字符、字符串、对象等。
- 指针(或引用):指向下一个节点的指针。它存储了下一个节点在内存中的地址,通过这个指针可以找到链表的下一个节点。

🌰单链表
单链表是最简单的链表类型,每个节点包含一个数据元素和一个指向下一个节点的指针。单链表的尾节点指针为空,表示链表的结束。单链表的插入、删除操作相对简单高效,但随机访问的效率较低。
结构图:

🥕单链表特点
-
非连续存储:单链表中的节点在内存中可以是任意位置,不要求连续存储。每个节点通过指针指向下一个节点,从而将它们连在一起。
-
动态性:相较于数组,单链表的长度可以动态地增减,不需要预先分配内存空间。这使得单链表在需要频繁插入和删除节点的场景中更加灵活。
-
搜索效率相对较低:由于单链表的节点只能通过指针一个一个地遍历,因此搜索某个特定的节点需要遍历整个链表,时间复杂度为O(n),其中n是链表的长度。相比之下,数组可以使用索引直接访问元素,搜索效率更高。
-
内存空间的额外开销:单链表中的每个节点除了存储数据外,还需要存储下一个节点的指针,这导致了额外的内存开销。
-
插入和删除效率较高:相对于数组,单链表在插入和删除节点时效率较高。插入一个节点只需要改变相邻节点的指针,而删除一个节点只需要改变前一个节点的指针指向下一个节点,不需要移动其他元素。
-
灵活性:单链表可以方便地进行节点的插入和删除操作,可以根据实际需要进行自由调整。
🌰双向链表
双向链表在单链表的基础上增加了一个指向前一个节点的指针,使得节点既能够往后访问,也能够往前访问。这样的设计使得插入和删除操作更加灵活便捷,但相应地占用了更多的存储空间。
结构图:

🥕双链表特点
-
支持双向遍历:相对于单向链表,双向链表支持双向遍历,可以从前往后、从后往前遍历链表。
-
插入、删除节点效率更高:相较于单向链表,双向链表在插入和删除某个节点时,只需要改变相邻两个节点的指向,效率更高,尤其是在删除链表中某个元素时更加便捷。
-
需要更多的内存空间:相比单向链表,双向链表需要更多的内存空间来存储额外的指针,增加了额外的空间开销。
-
内存存储不连续:相对于数组,链表中节点的内存存储位置不连续,需要使用指针进行串联,这可以更加灵活地进行插入、删除和移动节点的操作。
-
操作复杂度较高:插入、删除、移动等操作,需要修改前后节点的指针信息,操作比较繁琐。
🌰循环链表
循环链表是一种特殊的链表类型,链表的尾节点指针指向头节点,形成一个循环的结构。循环链表可以通过尾节点快速访问链表的头部,常用于某些特定场景,如循环队列的实现。
结构图:

🥕循环链表特点
-
首位相连:循环链表的最后一个节点指向链表的第一个节点,使得链表成为一个环形结构。这样,链表的结束节点与开始节点相连,可以实现无限循环,更加灵活和方便。
-
操作始终成立:由于循环链表始终是一个环形的结构,因此操作(例如插入、删除、查找等)始终处于链表中,这也保证了操作始终能够完成。
-
遍历循环:与单向链表相比,在遍历时需要注意指针不要陷入死循环。否则会导致遍历永远无法结束。
-
内存空间的额外开销:与单向链表相比,循环链表需要多一个指向头部节点的指针,增加了额外的空间开销。
-
插入和删除效率较高:相对于数组,循环链表在插入和删除节点时效率比较高。插入一个节点时只需要修改相邻节点的指针即可,而删除一个节点时只需要改变前一个节点的指针指向下一个节点即可。
🌰链表的操作
链表的常见操作包括插入、删除和查询。链表的插入操作可以在指定位置或者链表尾部插入一个节点,只需要调整相应节点的指针即可。链表的删除操作类似,只需要改变相应节点的指针即可删除指定节点。链表的访问操作需从头节点开始遍历,直到找到目标节点或遍历到链表尾部。同时,需要注意链表操作时需要处理特殊情况,如链表为空或插入删除节点是头节点或尾节点的情况。
🍆链表的插入
🫘链头插入

代码示例
class Node:def __init__(self, data):self.data = dataself.next = Nonedef insert_at_head(head, value):# 创建新节点new_node = Node(value)# 将新节点的下一个指针指向当前头节点new_node.next = head# 更新头节点为新节点head = new_nodereturn headdef display_linked_list(head):current = headwhile current:print(current.data, "-> ", end="")current = current.nextprint("NULL")# 创建一个空链表
head = None# 在头部插入节点
head = insert_at_head(head, 3)
head = insert_at_head(head, 2)
head = insert_at_head(head, 1)# 打印链表
display_linked_list(head)
打印结果:
1 -> 2 -> 3 -> NULL
🫘链间插入

程序示例:
class Node:def __init__(self, data):self.data = dataself.next = Nonedef insert_in_between(node, value):if not node:return Nonenew_node = Node(value)new_node.next = node.nextnode.next = new_nodedef display_linked_list(head):current = headwhile current:print(current.data, "-> ", end="")current = current.nextprint("NULL")# 创建一个链表
head = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)head.next = node2
node2.next = node3
node3.next = node4# 在节点2和节点3之间插入节点
insert_in_between(node2, 2.5)# 打印链表
display_linked_list(head)
打印结果:
1 -> 2 -> 2.5 -> 3 -> 4 -> NULL
🍆链表的删除
🫘链头删除

代码示例:
class Node:def __init__(self, data):self.data = dataself.next = Nonedef delete_at_head(head):if not head:return Nonenew_head = head.nexthead.next = Nonereturn new_headdef display_linked_list(head):current = headwhile current:print(current.data, "-> ", end="")current = current.nextprint("NULL")# 创建一个链表
head = Node(1)
node2 = Node(2)
node3 = Node(3)head.next = node2
node2.next = node3# 删除头节点
head = delete_at_head(head)# 打印链表
display_linked_list(head)
运行结果:
2 -> 3 -> NULL
🫘链间删除

示例代码:
class Node:def __init__(self, data):self.data = dataself.next = Nonedef delete_in_between(head, value):if not head:return Nonecurrent = headprev = Nonewhile current and current.data != value:prev = currentcurrent = current.nextif not current:return headif not prev:head = head.nextelse:prev.next = current.nextcurrent.next = Nonereturn headdef display_linked_list(head):current = headwhile current:print(current.data, "-> ", end="")current = current.nextprint("NULL")# 创建一个链表
head = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)head.next = node2
node2.next = node3
node3.next = node4# 删除节点3
head = delete_in_between(head, 3)# 打印链表
display_linked_list(head)
运行结果:
1 -> 2 -> 4 -> NULL
🍆链表的查询
代码示例:
class Node:def __init__(self, data):self.data = dataself.next = Nonedef search_node(head, value):current = headwhile current:if current.data == value:return Truecurrent = current.nextreturn False# 创建一个链表
head = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)head.next = node2
node2.next = node3
node3.next = node4# 查询节点3
found = search_node(head, 3)if found:print("节点找到")
else:print("节点未找到")
🌰链表的应用场景
链表在实际应用中有许多重要的应用场景。其中,LRU Cache(最近最少使用缓存)获取和替换缓存中的数据时,可以使用链表实现高效的插入和删除操作。链表反转可以使用链表的插入和删除操作实现,将原链表的节点反向连接,获得反转后的链表。另外,链表排序也是链表的经典应用之一,通过比较和交换链表节点的值,实现链表的排序操作。
🌰链表与数组的比较
链表和数组是两种不同的数据结构,它们在以下方面有所区别:
🌳存储方式
数组是一块连续的内存空间,可以通过下标访问任意位置的元素;而链表是由节点组成,每个节点包含数据和指向下一个节点的指针。
🌳插入和删除操作
在数组中,插入和删除操作可能需要移动其他元素以保持连续性,时间复杂度为 O(n);而链表中插入和删除操作只需要更新节点的指针,时间复杂度通常为 O(1)。
🌳访问效率
在数组中,通过下标可以直接访问元素,时间复杂度为 O(1);而链表需要从头节点开始遍历,平均情况下需要 O(n) 时间。
🌳空间效率
对于相同的元素数量,链表通常需要更多的空间,因为每个节点都需要额外的指针来指向下一个节点;而数组只需要连续的内存空间。
🌰结语
链表作为一种重要的数据结构,在算法和数据结构中扮演着重要的角色。通过深入理解链表的原理和操作,我们可以更好地应用它来解决实际问题。
链表的灵活性使得它在许多领域有着广泛的应用。其中,LRU Cache就是一个很好的例子。LRU Cache是一种常见的缓存策略,它会保留最近最常使用的数据,而淘汰最近最少使用的数据。这可以通过链表来实现。链表的头部表示最近最常使用的数据,而尾部表示最近最少使用的数据。当有新数据加入时,我们可以将其添加到链表的头部。而当缓存满时,我们可以淘汰链表尾部的数据。这就是链表的高效插入和删除操作在实际应用中的体现。
链表的反转也是一个重要的应用场景。通过链表的插入和删除操作,我们可以将原始链表的节点逐个取出,并依次插入到新链表的头部,从而实现链表的反转。这个过程只需要简单地修改指针的指向,时间复杂度为O(n),其中n为链表的长度。链表的反转在实际开发中经常遇到,比如反转字符串、反转链表以及翻转二叉树等。
此外,链表的排序也是另一个常见的应用场景。链表的排序可以采用排序算法中的一些经典方法,比如插入排序、归并排序和快速排序等。其中,归并排序在链表中有着很好的适用性。归并排序是一种分治的排序算法,通过递归地将链表划分为更小的子链表,然后将它们按顺序合并。这样,在每一层递归中,我们可以通过比较两个已排序的子链表的头部节点,选择较小的节点,进行合并。通过这种方式,我们可以实现链表的排序操作。
在选择使用链表还是数组时,我们需要根据实际情况权衡它们之间的优缺点。链表的插入和删除操作相对高效,而数组的随机访问效率较高。因此,在需要频繁插入和删除的场景下,链表是一个更好的选择。而在需要快速根据索引查找元素的场景下,数组更具优势。此外,在空间方面,链表需要额外的指针来连接节点,而数组则需要连续的存储空间。因此,如果内存空间有限,我们可能需要考虑使用链表。
总结起来,链表是一种重要的数据结构,具有许多广泛应用的场景。通过深入理解链表的原理和操作,我们可以更好地应用它来解决实际问题。无论是LRU Cache的实现、链表的反转还是链表的排序,都需要我们熟练掌握链表的特性和操作方法。
🏫博客主页:魔王-T
🏯系列专栏:结构算法
🥝大鹏一日同风起 扶摇直上九万里
❤️感谢大家点赞👍收藏⭐评论✍️
相关文章:
深入理解数据结构:链表
文章目录 🌰导语🌰链表的定义及基本结构🌰单链表🥕单链表特点 🌰双向链表🥕双链表特点 🌰循环链表🥕循环链表特点 🌰链表的操作🍆链表的插入🫘链头…...
7:kotlin 数组 (Arrays)
数组是一种数据结构,它保存固定数量的相同类型或其子类型的值。kotlin中最常见的数组类型是对象类型数组,数组由array类表示。 什么时候使用 当你在kotlin中有特殊的底层需求需要满足时,可以使用数组。例如,如果你有超出常规应用…...
mysql 变量和配置详解
MySQL 中还有一些特殊的全局变量,如 log_bin、tmpdir、version、datadir,在 MySQL 服务实例运行期间它们的值不能动态修改,也就是不能使用 SET 命令进行重新设置,这种变量称为静态变量。数据库管理员可以使用前面提到的修改源代码…...
算法基础之合并集合
合并集合 核心思想:并查集: 1.将两个集合合并2.询问两个元素是否在一个集合当中 基本原理:每个集合用一棵树表示 树根的编号就是整个集合的编号 每个节点存储其父节点,p[x]表示x的父节点 #include<iostream>using namespace std;const int N100010;int p[N];…...
在使用微信或者支付宝支付的时候,为什么微信支付或者支付宝支付的异步通知商户支付结果要进行验签?
在使用微信支付或支付宝支付等第三方支付平台时,异步通知是一种常见的机制,用于通知商户支付结果或交易状态的变化。验签(Signature Verification)是为了确保异步通知的安全性和完整性而进行的重要步骤。以下是为什么要进行验签的…...
带你用uniapp从零开发一个仿小米商场_5. 公共样式编写,
先前引入了公共样式,但公共样式文件里面还没有编写内容 在这里我将一一讲解公共样式内应该有什么样式,和为什么 首先给page添加高度和背景色,当然这个背景色可以在app.vue内添加 page{/* 设置page高,让每个页面的最小高度为整个视窗的高 */min-height: 100vh; /* 统一字体大小…...
2019年全国硕士研究生入学统一考试管理类专业学位联考英语(二)试题
文章目录 2019年考研英语二真题SectionⅠ Use of EnglishSection II Reading ComprehensionText 121——细节信息题22——细节信息题23——细节信息题24——细节信息题25——词义题 Text 226——细节信息题27——细节信息题28——细节信息题29——细节信息题30——态度题 Text …...
基于C#实现Kruskal算法
这篇我们看看第二种生成树的 Kruskal 算法,这个算法的魅力在于我们可以打一下算法和数据结构的组合拳,很有意思的。 一、思想 若存在 M{0,1,2,3,4,5}这样 6 个节点,我们知道 Prim 算法构建生成树是从”顶点”这个角度来思考的,然…...
卷积神经网络经典backbone
特征提取是数据分析和机器学习中的基本概念,是将原始数据转换为更适合分析或建模的格式过程中的关键步骤。特征,也称为变量或属性,是我们用来进行预测、对对象进行分类或从数据中获取见解的数据点的特定特征或属性。 1.AlexNet paper&#…...
【2023 年终盘点】今年用的最多的 10 款浏览器插件
分享顺哥今年用的最多的 10 款浏览器插件。 排名不分先后,涉及各个方面的应用。 大家有好用的插件也欢迎在评论区留言分享! 视频 YouTube:https://youtu.be/ZpTydUSBwCA 顺哥博客 浏览器扩展篇 注意: 1、以下介绍的均为在 Google Chrome 浏览器适用的小插件,部分插件…...
GWAS:plink进行meta分析
之前教程提到过Metal是可以做Meta分析,除了Metal,PLINK也可以进行Meta分析。 命令如下所示: plink --meta-analysis gwas1.plink gwas2.plink gwas3.plink logscale qt --meta-analysis-snp-field SNP --meta-analysis-chr-field CHR --me…...
web:[WUSTCTF2020]朴实无华
题目 点开页面显示如下 页面显示了一行报错:Cannot modify header information - headers already sent by (output started at /var/www/html/index.php:3) in /var/www/html/index.php on line 4 意思为不能修改报头信息-报头已经发送(输出开始于/var/www/html/i…...
云原生安全工具汇总(docker、k8s、Kubernetes、Git仓库)
目录 Metarget:云原生靶机环境 CDK:容器环境定制的渗透测试工具 container-escape-check:容器逃逸检测...
基于51单片机超声波测距汽车避障系统
**单片机设计介绍, 基于51单片机超声波测距汽车避障系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于51单片机的超声波测距汽车避障系统是一种用于帮助汽车避免碰撞和发生事故的设备,以下是一个基本…...
git的使用:本地git下载、sshkey的添加、github仓库创建及文件上传
一、github创建账号 即github注册账号,登录github官网,根据提示注册即可 github官网 二、git客户端下载安装 已有很多git下载安装的博文了,在此就不赘述 三、sshkey的生成与添加 1、sshkey的生成以及查看 // sshkey的生成命令ÿ…...
增量有余、后劲不足,星途汽车10月份销量环比下降3.9%
撰稿|行星 来源|贝多财经 近日,奇瑞集团发布了10月销量月报。报告显示,奇瑞集团于2023年10月销售汽车20.03万辆,同比增长50.8%,单月销量首次突破20万辆;2023年前10个月的累计销量为145.36辆,同比增长41.6…...
只考数据结构,计算机评级C+,成都信息工程大学考情分析
成都信息工程大学(C) 考研难度(☆☆) 内容:23考情概况(拟录取和复试分析)、院校概况、24专业目录、23复试详情、各专业考情分析、各科目考情分析。 正文1715字,预计阅读:3分钟 2023考情概况 …...
Screen操作
detach:detach是指将当前运行的Screen会话从终端分离(detach),使其在后台继续运行而不受当前终端窗口的影响。这样,你可以在一个终端窗口中启动一个Screen会话,然后在需要的时候将其分离,使其在…...
js基础知识
1. beforeCreate 初始化界面前 : 在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。 2. created 初始化界面后 : 在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更…...
Vue常见的实现tab切换的两种方法
目录 方法一:事件绑定属性绑定 效果图 完整代码 方法二:属性绑定 动态组件 component标签 效果图 完整代码 方法一:事件绑定属性绑定 效果图 完整代码 <!DOCTYPE html> <html lang"en"> <head><meta c…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...
