当前位置: 首页 > news >正文

5. 链表

内存空间是所有程序的公共资源,在一个复杂的系统运行环境下,空闲的内存空间可能散落在内存各处。我们知道,存储数组的内存空间必须是连续的,而当数组非常大时,内存可能无法提供如此大的连续空间。此时链表的灵活性优势就体现出来了。

链表(linked list)是一种线性数据结构,其中的每个元素都是一个节点对象,各个节点通过“引用”相连接。引用记录了下一个节点的内存地址,通过它可以从当前节点访问到下一个节点。

链表的设计使得各个节点可以被分散存储在内存各处,它们的内存地址是无须连续的。

观察上图 ,链表的组成单位是节点 (node)对象。每个节点都包含两项数据:节点的“值”和指向下一节点的“引用”。

  • 链表的首个节点被称为“头节点”,最后一个节点被称为“尾节点”。
  • 尾节点指向的是“空”,它在 Java、C++ 和 Python 中分别被记为 \(\text{null}\)、\(\text{nullptr}\) 和 \(\text{None}\) 。
  • 在 C、C++等支持指针的语言中,上述的“引用”应被替换为“指针”。

 如以下代码所示,链表节点 ListNode 除了包含值,还需额外保存一个引用(指针)。因此在相同数据量下,链表比数组占用更多的内存空间

/* 链表节点结构体 */
struct ListNode {int val;         // 节点值ListNode *next;  // 指向下一节点的指针ListNode(int x) : val(x), next(nullptr) {}  // 构造函数
};

5.1 链表常用操作

5.1.1 初始化链表

 建立链表分为两步,第一步是初始化各个节点对象,第二步是构建引用指向关系。初始化完成后,我们就可以从链表的头节点出发,通过引用指向 next 依次访问所有节点。

/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
// 初始化各个节点
ListNode* n0 = new ListNode(1);
ListNode* n1 = new ListNode(3);
ListNode* n2 = new ListNode(2);
ListNode* n3 = new ListNode(5);
ListNode* n4 = new ListNode(4);
// 构建引用指向
n0->next = n1;
n1->next = n2;
n2->next = n3;
n3->next = n4;

数组整体是一个变量,比如数组 nums 包含元素 nums[0] 和 nums[1] 等,而链表是由多个独立的节点对象组成的。我们通常将头节点当作链表的代称,比如以上代码中的链表可被记做链表 n0 。

5.1.2 插入节点

在链表中插入节点非常容易。如下图所示,假设我们想在相邻的两个节点 n0 和 n1 之间插入一个新节点 P ,则只需要改变两个节点引用(指针)即可,时间复杂度为O(1)。

相比之下,在数组中插入元素的时间复杂度为O(n),在大数据量下的效率较低。

/* 在链表的节点 n0 之后插入节点 P */
void insert(ListNode *n0, ListNode *P) {ListNode *n1 = n0->next;P->next = n1;n0->next = P;
}

5.1.3 删除节点

如下图所示,在链表中删除节点也非常方便,只需改变一个节点的引用(指针)即可。请注意,尽管在删除操作完成后节点 P 仍然指向 n1 ,但实际上遍历此链表已经无法访问到 P ,这意味着 P 已经不再属于该链表了。

/* 删除链表的节点 n0 之后的首个节点 */
void remove(ListNode *n0) {if (n0->next == nullptr)return;// n0 -> P -> n1ListNode *P = n0->next;ListNode *n1 = P->next;n0->next = n1;// 释放内存delete P;
}

5.1.4 访问节点

在链表访问节点的效率较低。如上节所述,我们可以在 \(O(1)\) 时间下访问数组中的任意元素。链表则不然,程序需要从头节点出发,逐个向后遍历,直至找到目标节点。也就是说,访问链表的第 i个节点需要循环i - 1轮,时间复杂度为 O(n) 。

/* 访问链表中索引为 index 的节点 */
ListNode *access(ListNode *head, int index) {for (int i = 0; i < index; i++) {if (head == nullptr)return nullptr;head = head->next;}return head;
}

5.1.5 查找节点

遍历链表,查找链表内值为 target 的节点,输出节点在链表中的索引。此过程也属于线性查找。

/* 在链表中查找值为 target 的首个节点 */
int find(ListNode *head, int target) {int index = 0;while (head != nullptr) {if (head->val == target)return index;head = head->next;index++;}return -1;
}

5.2 数组 VS 链表

下表总结对比了数组和链表的各项特点与操作效率。由于它们采用两种相反的存储策略,因此各种性质和操作效率也呈现对立的特点。

5.3 常见链表类型

如下图所示,常见的链表类型包括三种。

  • 单向链表:即上述介绍的普通链表。单向链表的节点包含值和指向下一节点的引用两项数据。我们将首个节点称为头节点,将最后一个节点称为尾节点,尾节点指向空 \(\text{None}\) 。
  • 环形链表:如果我们令单向链表的尾节点指向头节点(即首尾相接),则得到一个环形链表。在环形链表中,任意节点都可以视作头节点。
  • 双向链表:与单向链表相比,双向链表记录了两个方向的引用。双向链表的节点定义同时包含指向后继节点(下一个节点)和前驱节点(上一个节点)的引用(指针)。相较于单向链表,双向链表更具灵活性,可以朝两个方向遍历链表,但相应地也需要占用更多的内存空间。
/* 双向链表节点结构体 */
struct ListNode {int val;         // 节点值ListNode *next;  // 指向后继节点的指针ListNode *prev;  // 指向前驱节点的指针ListNode(int x) : val(x), next(nullptr), prev(nullptr) {}  // 构造函数
};

5.4 链表典型应用

单向链表通常用于实现栈、队列、哈希表和图等数据结构。

  • 栈与队列:当插入和删除操作都在链表的一端进行时,它表现出先进后出的的特性,对应栈;当插入操作在链表的一端进行,删除操作在链表的另一端进行,它表现出先进先出的特性,对应队列。
  • 哈希表:链地址法是解决哈希冲突的主流方案之一,在该方案中,所有冲突的元素都会被放到一个链表中。
  • :邻接表是表示图的一种常用方式,在其中,图的每个顶点都与一个链表相关联,链表中的每个元素都代表与该顶点相连的其他顶点。

双向链表常被用于需要快速查找前一个和下一个元素的场景。

  • 高级数据结构:比如在红黑树、B 树中,我们需要访问节点的父节点,这可以通过在节点中保存一个指向父节点的引用来实现,类似于双向链表。
  • 浏览器历史:在网页浏览器中,当用户点击前进或后退按钮时,浏览器需要知道用户访问过的前一个和后一个网页。双向链表的特性使得这种操作变得简单。
  • LRU 算法:在缓存淘汰算法(LRU)中,我们需要快速找到最近最少使用的数据,以及支持快速地添加和删除节点。这时候使用双向链表就非常合适。

循环链表常被用于需要周期性操作的场景,比如操作系统的资源调度。

  • 时间片轮转调度算法:在操作系统中,时间片轮转调度算法是一种常见的 CPU 调度算法,它需要对一组进程进行循环。每个进程被赋予一个时间片,当时间片用完时,CPU 将切换到下一个进程。这种循环的操作就可以通过循环链表来实现。
  • 数据缓冲区:在某些数据缓冲区的实现中,也可能会使用到循环链表。比如在音频、视频播放器中,数据流可能会被分成多个缓冲块并放入一个循环链表,以便实现无缝播放。

相关文章:

5. 链表

内存空间是所有程序的公共资源&#xff0c;在一个复杂的系统运行环境下&#xff0c;空闲的内存空间可能散落在内存各处。我们知道&#xff0c;存储数组的内存空间必须是连续的&#xff0c;而当数组非常大时&#xff0c;内存可能无法提供如此大的连续空间。此时链表的灵活性优势…...

OSI七层模型与TCP/IP四层模型的区别(计算机网络)

一、OSI七层网络模型 OSI 网络模型共有 7 层&#xff0c;分别是应用层、表示层、会话层、传输层、网络层、数据链路层和物理层。 应用层&#xff0c;负责给应用程序提供统一的接口&#xff1b;表示层&#xff0c;负责把数据转换成兼容另一个系统能识别的格式&#xff1b;会话…...

Other--什么是 CGI,FastCGI、asp、jsp

文章目录 1. 了解什么是动态网页2. 什么是 CGI2.1 CGI 概念2.2 CGI 功能2.3 CGI 作用2.4 CGI 分类2.5 CGI 程序的工作原理2.6 CGI 程序的特点2.7 CGI 程序的应用领域4. 什么是 FastCGI4.1 FastCGI 概念4.2 FastCGI 程序工作原理4.3 FastCGI 对进程的管理方式4.4 FastCGI 的特点…...

sql关联另一个表,update表的值

sql示例&#xff1a; update student_score ss set ss.names.name from student s where ss.codes.code 最常见的学生成绩表 student_score通过学生student_code关联学生信息表student 学生信息表&#xff08;student&#xff09;&#xff1a; code name age gender 1001 …...

Python基础:JSON保存结构化数据(详解)

1. JSON概念 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;易于人阅读和编写&#xff0c;也易于机器解析和生产。   虽然JSON使用JavaScript语法来描述数据对象&#xff0c;但是JSON仍然独立于语言和平台&#xff0c;JSON解…...

抑郁症日常如何调节?

抑郁症是一种常见的心理障碍&#xff0c;影响患者的情绪、思维和身体健康。以下是一些建议&#xff0c;帮助抑郁症患者进行日常调节&#xff1a; 保持积极心态&#xff1a;积极的心态是应对抑郁症的关键。尝试保持乐观、积极的态度&#xff0c;看待生活中的困难和挑战。尽管抑…...

hive两张表实现like模糊匹配关联

testa表(字段a)aaabbacccddddddaaatestb表(字段b)ab1. 使用likeconcat模糊配对 selecta.a from testa a ,testb b where a like concat(%,b.b,%) group by a.a2. 使用locate函数 selecta.a from testa a ,testb b where locate(b.b,a.a)>0 group by a.a3. 使用instr函数 sel…...

【高效开发工具系列】Hutool DateUtil工具类

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

基于springcloud openfein 使用示例,包含代码和 maven 依赖配置

使用 Spring Cloud 和 OpenFeign 可以轻松实现微服务之间的通信。以下是一个简单的示例&#xff0c;演示如何在Spring Boot应用中使用Spring Cloud OpenFeign。 首先&#xff0c;确保您的项目中添加了 Spring Cloud 和 OpenFeign 的依赖。这里提供 Maven 依赖配置&#xff1a;…...

彰显营销硬实力!皓量科技连续四年入选《中国数字营销生态图》

11月28日&#xff0c;中国商务广告协会数字营销专业委员会、虎啸奖组委会、秒针营销科学院共同发布了《中国数字营销生态图&#xff08;2023版&#xff09;》&#xff08;以下简称生态图&#xff09;。凭借多年在广告营销领域的精耕细作&#xff0c;皓量科技从2020年开始连续4年…...

web静态网页设计与制作-基于HTML+CSS+JS实现旅游摄影网站

web静态网页设计与制作&#xff0c;基于HTMLCSSJS实现精美的旅游摄影网站&#xff0c;拥有极简的设计风格&#xff0c;丰富的交互动效&#xff0c;让人眼前一亮&#xff0c;享受视觉上的体验。 我使用了基本的HTML结构来构建网页&#xff0c;并使用CSS样式进行美化设计&#xf…...

每日一题:LeetCode-1089. 复写零

每日一题系列&#xff08;day 09&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…...

React Native环境搭建及Hello World

写这篇博客的目的就是想说,react native 挺简单,但是大部分初级前端会被环境搭建给难住,从而放弃. 环境搭建 环境搭建其实说简单也挺简单的,有经验的前端直接翻看react native中文文档就行,直接按上面来肯定没错 以下以安卓开发,windows配置环境为例,来演示一遍 首先 电脑…...

VS2017 C++ Qt工程打包软件

在Debug模式下或者Release模式下编译成功&#xff0c;会在工程的Debug文件夹和Release文件夹生成exe执行文件&#xff0c;以Debug为例&#xff0c;将Debug模式下的exe复制到新的文件夹路径下&#xff0c;然后打开Qt中的MSVC 2017 64-bit 打开后然后在命令窗口cd到exe的路径下&…...

【JWT的原理和使用】

JSON Web Token&#xff08;缩写 JWT&#xff09;是目前最流行的跨域认证解决方案&#xff0c;本文介绍它的原理和用法。 文章目录 一、跨域认证的问题二、JWT 的原理三、JWT 的数据结构3.1 Header3.2 Payload3.3 Signature3.4 Base64URL 四、JWT 的使用方式五、JWT 的几个特点…...

对本地存储的有效期的理解

本地存储是一种在Web开发中常用的客户端存储数据的方式&#xff0c;它可以让网页应用程序在用户的浏览器中存储和检索数据&#xff0c;而无需依赖服务器来保存信息。本地存储的有效期是指数据存储在用户的设备上可以被访问和保留的时间段。在本地存储中&#xff0c;有两种主要的…...

蓝桥杯-02-蓝桥杯Java组考点与14届真题

文章目录 蓝桥杯Java组考点与14届真题参考资源Java组考点1. 组别2. 竞赛赛程3. 竞赛形式4. 参赛选手机器环境5. 试题形式5.1. 结果填空题5.2. 编程大题 6. 试题考查范围7. 答案提交8. 评分9. 样题样题 1&#xff1a;矩形切割&#xff08;结果填空题&#xff09;样题 2&#xff…...

门户网站二级等保评测问题,服务器漏洞问题解决办法

二级等保查出来的服务器问题 操作前可在自己服务器测试一下&#xff0c;看看有没有用 1.服务器定时更换密码 永久&#xff08;需重启&#xff09; vim /etc/login.defs PASS_MAX_DAYS 90 # 密码最长过期天数 PASS_MIN_DAYS 0 # 密码最小过期天数 PASS_MIN_LEN 10 # 密码…...

NPDP考前注意事项,这些细节你可要注意!

产品经理国际资格产认证&#xff08;NPDP&#xff09;2023年考试将于2023年12月2日&#xff08;本周六&#xff09;进行&#xff0c;你准备好了吗&#xff1f; 考试详情 考试时间&#xff1a;2023年12月2日 上午9:00-12:30 考试题型&#xff1a;200题&#xff0c;单选题。 考…...

八个优秀开源内网穿透工具

内网穿透&#xff08;NAT穿透&#xff09;是一种将本地网络服务暴露给互联网的一种技术。这种技术可以很好地解决许多局域网内的资源共享。采用路由的方式将一台计算机变成一个“路由器”&#xff0c;将公共的网络地址转为内部网络地址&#xff0c;从而实现通过英特网可以访问局…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...