【数据结构与算法】4.自主实现单链表的增删查改

📚博客主页:爱敲代码的小杨.
✨专栏:《Java SE语法》
❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️
🙏小杨水平有限,欢迎各位大佬指点,相互学习进步!

文章目录
- 1. 前言
- 2. 链表
- 3. 单链表的实现
- 3.1 打印链表
- 3.2 头插法
- 3.3 尾插法
- 3.4 任意位置插入元素
- 3.5 查找元素
- 3.6 链表节点个数
- 3.7 删除元素
- 3.8 删除链表中指定的所有元素
- 3.9 清空链表
- 4. 代码
1. 前言
在上一篇《顺序表》中,我们已经熟悉了 ArrayList 的使用并且进行了简单的模拟实现。ArrayList底层使用数组来存储元素,由于其底层是一段连续的空间,当ArrayList 任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后移动,时间复杂度为O(n),效率比较低,因此ArrayList 不适合做任意位置插入和删除比较多的场景。因此:Java集合这种又引入了 LinkedList,即链表结构。
2. 链表
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中引用链接次序实现的。

注意:
- 从上图可看出,链表结构正在逻辑上是连续的,但是在物理上(内存)不一定连续。
- 现实中的节点一般都是从堆上申请出来的。
- 从堆上申请的空间,是按照一定的额策略来分配的,两次申请的空间可能连续,也可能不连续。
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
-
单向或者双向

-
带头或者不带头

-
循环或者非循环

虽然有这么多的链表结构,但是我们重点掌握两种:
- 无头单向非循环链表:结构简单,一般不会单独用来存放数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。
- 无头双向链表:在Java的集合类中
LinkedList底层实现就是无头双向循环链表
3. 单链表的实现
创建一个链表
public class MySingleList {// 节点static class ListNode {public int val; // 数值域 - 存放当前节点的值public ListNode next; // next域 指向下一个节点public ListNode(int val) {this.val = val;}}// 链表的属性 链表的头节点public ListNode head; // nullpublic void createList() {ListNode node1 = new ListNode(1);ListNode node2 = new ListNode(2);ListNode node3 = new ListNode(3);ListNode node4 = new ListNode(4);node1.next = node2;node2.next = node3;node3.next = node4;this.head = node1;}
}
画图表示:

3.1 打印链表
-
怎么从第一个节点走到第二个节点?
答:
head = head.next -
什么时候算是把节点都遍历完成?
答:
head == null
代码实现:
/**** 打印链表*/@Overridepublic void display() {ListNode cur = head;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;// 让cur这个节点 可以从一个节点走到下一个节点}System.out.println();}
3.2 头插法
在链表的第一个位置插入元素。
思路:
- 插入元素的
next指向head head指向插入元素

代码实现:
/*** 头插法* @param data*/@Overridepublic void addFirst(int data) {ListNode node = new ListNode(data); // 定义一个节点node.next = head;head = node;}
3.3 尾插法
在链表的最后个位置插入元素
思路:
- 判断链表中是否有元素。
- 如果没有元素,直接添加头结点即可。
- 如果有元素,将原链表最后一个元素
next指向插入的元素。

代码实现:
/*** 尾插法* @param data*/@Overridepublic void addLast(int data) {ListNode node = new ListNode(data); // 定义一个节点if (head == null) { // 链表一个元素都没有head = node;} else {ListNode cur = head;while (cur.next != null) {cur = cur.next;}cur.next = node;}}
3.4 任意位置插入元素
思路:
- 判断
index是否合法(index < 0 或者 index 大于链表长度),如果不合法则抛出异常。 - 判断
index等于0或者index等于链表长度,则使用头插法或尾插法 cur找到index - 1位置- 插入元素的
next指向cur的next cur的next指向插入的元素

代码实现:
/*** 在index位置 插入data* @param index* @param data*/@Overridepublic void addIndex(int index, int data) throws IndexException{if (index < 0 || index > size()) {throw new IndexException("index不合法:" + index);}ListNode node = new ListNode(data); // 定义一个节点if (head == null) {head = node;return;}if (index == 0) {addFirst(data);return;}if (index == size()) {addLast(data);return;}ListNode cur = searchPrevIndex(index);node.next = cur.next;cur.next = node;}/*** 找到index-1的位置* @param index* @return*/private ListNode searchPrevIndex(int index) {ListNode cur = head;int count = 0;while (count != index - 1) {cur = cur.next;count++;}return cur;}
异常类:
public class IndexException extends RuntimeException{public IndexException() {}public IndexException(String msg) {super(msg);}
}
3.5 查找元素
代码实现:
/**** 求当前链表 是否存在key* @param key* @return*/@Overridepublic boolean contains(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}
3.6 链表节点个数
代码实现:
/*** 求当前链表 有多少个节点* @return*/@Overridepublic int size() {ListNode cur = head;int count = 0;while (cur != null) {count++;cur = cur.next;}return count;}
3.7 删除元素
思路:
- 判断链表是否为空,如果为空直接返回
- 判断删除元素是否为头节点,如果是则
head指向head的next - 定义指针找到要删除节点的前一个节点
- 前一个节点的
next指向删除节点的next

代码实现:
/**** @param key*/@Overridepublic void remove(int key) {if (head == null) {return;}if (head.val == key) {head = head.next;return;}ListNode cur = findPrevKey(key);if (cur == null) {return;// 链表里要没有删除的数字}ListNode del = cur.next;cur.next = del.next;}/*** 找到删除节点的前一个节点* @param key* @return*/private ListNode findPrevKey(int key) {ListNode cur = head;while (cur.next != null) {if (cur.next.val == key) {return cur;} else {cur = cur.next;}}return null;}
3.8 删除链表中指定的所有元素
思路:
- 判断链表是否为空,如果是空直接返回
- 定义指针
cur:可能要删除的节点 - 定义指针
prev:可能要删除的节点的前驱 - 判断
cur的val是不是要删除的元素,如果是prev的next指向cur的next,cur指向cur的next;否则prev指向cur,cur指向cur的next - 判断头节点的
val是否为的元素,如果是头节点指向头节点的neext

代码实现:
/*** 删除链表中所有的key* @param key*/@Overridepublic void removeAllKey(int key) {if (head == null) {return;}ListNode prev = head; // 表示当前可能要删除的节点ListNode cur = head.next; // 可能要删除节点的前驱while (cur != null) {if (cur.val == key) {prev.next = cur.next;cur = cur.next;} else {prev = cur;cur = cur.next;}}if (head.val == key) {head = head.next;}}
3.9 清空链表
当一个对象,没有被引用的时候,就会被回收掉
/*** 清空链表*/@Overridepublic void clear() {head = null;}
4. 代码
代码链接🔗

相关文章:
【数据结构与算法】4.自主实现单链表的增删查改
📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️ 🙏小杨水平有限,欢迎各位大佬指点&…...
Linux系统常用命令行指令
Linux系统是一种常用于开源项目开发的生产环境,因其免费、开源、安全、稳定的特点被广泛应用于手机、平板电脑、路由器、电视和电子游戏机等嵌入式系统中,能够更加简便地让用户知道系统是怎样工作的。前几日我安装好了Red Hat Enterprise Linux 9.0&…...
java SSM园林绿化管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计
一、源码特点 java SSM园林绿化管理系统是一套完善的web设计系统(系统采用SSM框架进行设计开发,springspringMVCmybatis),对理解JSP java编程开发语言有帮助,系统具有完整的源代 码和数据库,系统主要采…...
【issue-halcon例程学习】edges_color.hdev
例程功能 演示如何使用edges_color,展示只能从彩色图像中提取某些边缘的图像,说明edges_color和edges_image输出之间的差异。 代码如下 dev_update_off () read_image (Image, olympic_stadium) get_image_size (Image, Width, Height) dev_close_wind…...
设计模式—行为型模式之备忘录模式
设计模式—行为型模式之备忘录模式 备忘录(Memento)模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模…...
CMS如何调优
业务JVM频繁Full GC如何排查 原则是先止损,再排查。 FGC的原因是对象晋升失败或者并发模式失败,原因都是老年代放不下晋升的对象了。 1.可能是大对象导致的内存泄漏。快速排查方法:观察数据库网络IO是否和FGC时间点吻合,找到对应…...
在PyCharm中安装GitHub Copilot插件,login之后报出如下错误:
Sign in failed. Reason: Request signInInitiate failed with message: connect ECONNABORTED 20.205.243.166:443, request id: 7, error code: -32603 前提: 设置网址:https://github.com/settings/copilot,已设置为允许 或者࿱…...
L1-093 猜帽子游戏(Java)
宝宝们在一起玩一个猜帽子游戏。每人头上被扣了一顶帽子,有的是黑色的,有的是黄色的。每个人可以看到别人头上的帽子,但是看不到自己的。游戏开始后,每个人可以猜自己头上的帽子是什么颜色,或者可以弃权不猜。如果没有…...
JVM篇--JVM调优高频面试题
1 说一下 JVM 调优的工具? JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是jconsole 和 jvisualvm 这两款视图监控工具。 jconsole:用于对 JVM 中的内存、线程和类等进行监控; jvisualvm:…...
微软 AD 介绍 | 安全建议 | 防护
介绍: 什么是Active Directory(AD)? Active Directory 是由 微软开发的目录服务,用于存储和管理网络中的资源,如计算机、用户、组和其他网络对象。允许组织管理员轻松地管理和验证网络中的用户和计算机。 …...
React16源码: React中的reconcileChildren的源码实现
reconcileChildren 1 )概述 在更新了一个节点之后,拿到它的props.children要根据这个children里面的 ReactElement 来去创建子树的所有的 fiber 对象要根据 props.children 来生成 fiber 子树,然后判断 fiber 对象它是否是可以复用的 因为我…...
幻兽帕鲁Docker服务端搭建
幻兽帕鲁Docker服务端搭建 各种命令 https://bbs.saraba1st.com/2b/thread-2168983-1-1.html 存档恢复 这里直接看这个工程的readme就行:https://github.com/yoko-murasame/palworld-host-save-fix 其他参考:https://forum.gamer.com.tw/C.php?bsn7…...
【ARM Cortex-M 系列 1.1 -- Cortex-M33 与 M4 差异 详细介绍】
请阅读【嵌入式开发学习必备专栏 之 Cortex-Mx 专栏】 文章目录 背景Cortex-M33 与 M4 差异Cortex-M33Cortex-M4关系和差异举例说明 背景 在移植 RT-Thread 到 瑞萨RA4M2(Cortex-M33)上时,遇到了hardfault 问题,最后使用了Cortex…...
docker 部署及命令
一、容器概述 1、为什么要用到容器? ①容器可以屏蔽底层操作系统的差异性,让业务应用不管在哪里都是使用容器的环境运行,从而保证开发测试环境与生产环境的一致性 ②容器部署起来非常便捷和迅速,缩短开发测试部署的周期时间 2…...
API接口安全总结
接口分类 HTTP接口 RPC接口(客户端和服务器端的连接 例如游戏登陆)非web协议,PRC 远程过程调用 Remote Procedure Call,其就是一个节点请求另外一个节点提供的服务。当两个物理分离的子系统需要建立逻辑上的关联时,R…...
性能优化-HVX 指令介绍
「发表于知乎专栏《移动端算法优化》」 本文主要介绍了 HVX 指令相关的知识,包括 HVX 寄存器相关内容,指令的背景依赖,部分常用 intrinsic HVX 指令。具体指令的详细内容及使用还需阅读 HVX 的指令文档,以及细致的实践操作。 &…...
web安全思维导图(白帽子)
web安全思维导图(白帽子) 客户端脚本安全 服务端应用安全 白帽子讲web安全 安全运营体系建设...
美,英,法,德、意大利和西班牙的geojson,以及区域json
美,英,法,德、意大利和西班牙的geojson文件 json地址 https://pan.baidu.com/s/1nio1bV_j-jAEVqgEHXWsNw?pwdqwer#list/path/GEOJSON 感谢大佬提供的 大佬连接 大佬的知乎原地址 国内geojson获取工具地址 http://dauser: ,toke…...
在Windows虚拟机中挂载IP代理的流程
在虚拟机中挂载IP代理的步骤通常依赖于所使用的虚拟机软件(如VMware、VirtualBox等)以及代理服务器类型(HTTP/HTTPS/SOCKS)。以下是一个通用流程: 在Windows虚拟机中设置网络代理以使用代理IP: 1. SOCKS或H…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
