【Java数据结构】详解LinkedList与链表(一)
🔒文章目录:
1.❤️❤️前言~🥳🎉🎉🎉
2.ArrayList的缺陷
3.链表的概念及结构
4.无头单向非循环链表的实现
4.1成员属性
4.2成员方法
createList
display——打印链表
addFirst——头插
addLast——尾插
size——获取单链表长度
addIndex——在任意位置插入
contains——判定是否包含某个元素
remove——删除第一次出现关键字为key的结点
removeAll——删除所有值为key的结点
clear——清空单链表
4.3完整代码及使用
完整代码
完整代码的使用
5.总结
1.❤️❤️前言~🥳🎉🎉🎉
Hello, Hello~ 亲爱的朋友们👋👋,这里是E绵绵呀✍️✍️。
如果你喜欢这篇文章,请别吝啬你的点赞❤️❤️和收藏📖📖。如果你对我的内容感兴趣,记得关注我👀👀以便不错过每一篇精彩。
当然,如果在阅读中发现任何问题或疑问,我非常欢迎你在评论区留言指正🗨️🗨️。让我们共同努力,一起进步!
加油,一起CHIN UP!💪💪
🔗个人主页:E绵绵的博客
📚所属专栏:1. JAVA知识点专栏
深入探索JAVA的核心概念与技术细节
2.JAVA题目练习
实战演练,巩固JAVA编程技能
3.c语言知识点专栏
揭示c语言的底层逻辑与高级特性
4.c语言题目练习
挑战自我,提升c语言编程能力
📘 持续更新中,敬请期待❤️❤️

借鉴文章:Java【链表】详细图解/ 模拟实现+【LinkedList】常用方法介绍_java linkedlist方法-CSDN博客
2.ArrayList的缺陷
上篇文章已经熟悉了ArrayList的使用,并且进行了简单模拟实现。通过源码知道,ArrayList底层使用数组来存储元素
但由于其底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后 搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。
所以:java 集合中又引入了LinkedList,即链表结构。
3.链表的概念及结构
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

注意:
1.从上图可看出,链式结构在逻辑上是连续的,但是在物理上不一定连续
2.其结点一般都是从堆上申请出来的
3.从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可能连续,也可能不连续
🎯🎯实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
1. 单向或者双向
2.带头或者不带头
3. 循环或者非循环
虽然有这么多的链表的结构,但是我们重点掌握两种:
1.无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如 哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
2.无头双向非循环链表:在Java的集合框架库中LinkedList底层实现就是无头双向非循环链表。
4.无头单向非循环链表的实现
4.1成员属性
要模拟实现链表,也得自己实现一个类,首先要考虑这个类中的成员属性
已经说过,链表是由多个结点 “链接” 而成的,那么需要定义一个 静态内部类 Node:其中有两个域:
📌值域 value :来记录这个结点的值
📌指针域 next:来记录下一个结点的地址📌并且它还需要一个构造方法:在创建ListNode内部类的同时分配好value的值。
📌模拟的链表中还需要一个 成员变量:head 来记录当前链表的头结点。
public class SingleLinkedList {static class ListNode{public int value;public ListNode next;public ListNode(int value) {this.value = value;}}public ListNode head;
4.2成员方法
createList
该方法是我们自己为了方便独创的,实际链表方法中并不存在该方法。
public void createList(){ListNode listNode1 = new ListNode(45);ListNode listNode2 = new ListNode(46);ListNode listNode3 = new ListNode(50);ListNode listNode4 = new ListNode(56);ListNode listNode5 = new ListNode(67);listNode1.next=listNode2;listNode2.next=listNode3;listNode3.next=listNode4;listNode4.next=listNode5;head=listNode1;}该方法创建了一个内部节点为5个的无头单向非循环链表。(注意结尾head要指向ListNode1,否则该链表之后会自动被释放掉)
display——打印链表
注意:LinkedList 中不存在该方法,为了方便看测试结果
public void display(){ListNode cur=head;while(cur!=null){System.out.print(cur.value+" ");cur=cur.next;}System.out.println();}
addFirst——头插
❗️❗️和顺序表不同,链表是由一个个结点组成的,而顺序表可以理解为一个数组
顺序表插入之前必须考虑数组是否以及满了,而链表只需要关心各个结点的next即可。因为我们还有一个成员属性:head,是用来记录头结点的
所以链表的头插操作就是:
1️⃣new 一个结点 node,类型是 Node
2️⃣链接:把头结点的地址( head 的值)赋给 node 的指针域 next
3️⃣head 记录新的头结点public void addFirst(int a){ListNode listNode = new ListNode(a);listNode.next=head;head=listNode; }
addLast——尾插
尾插步骤:
1️⃣new 一个 node,类型是 Node
2️⃣找到尾结点
3️⃣链接:把 node 的值(也就是地址)赋给尾结点的指针域 next🚗🚗🚗
如何找到尾结点呢❓
需要 从头结点开始,遍历链表,找到一个结点的指针域 next 域为 null,它就是尾结点✅head 是用来标记头结点的,所以 head 不能随意更改
我们需要再定义一个 Node 类型的 cur,让 cur 遍历链表当 cur 找到尾结点后,需要让此时的尾结点和新结点 node 连接上
即如下图:并且我们还需要注意一个特殊情况:
cur 这个变量中存放的值 要更改为下一个结点的地址:cur = cur.next;但当cur == null 时,这里就会发生空指针异常❌,那么在实例中是否会出现这种情况?
如果 head 一开始就是 null ,也就是链表为空时,cur 就会被 head 赋值成 null,就会发生空指针异常。所以当链表为空时,就不需要遍历链表找尾结点,直接把 node 的值赋给 head 即可。
public void addLast(int a){ListNode listNode = new ListNode(a);ListNode cur=head;if(head==null){head=listNode;return; }while(cur.next!=null){cur=cur.next;}cur.next=listNode; }
size——获取单链表长度
直接遍历链表即可
public int size(){int count=0;ListNode cur=head;while(cur!=null){cur=cur.next;count++;}return count;}
addIndex——在任意位置插入
官方规定第一个数据的位置是0,和数组的位置(下标)规则一致
所以我们首先要判断 index 的合法性:index<0 || index >链表长度是不合法❌的
index 合法的情况下,如何在index位置插入删除呢❓
📌index == 0就是头插
📌index = 链表长度就是尾插
❗️主要是链表中间位置的插入和删除
要想在两个结点中间插入新结点,首先要找到这两个结点的地址
找到 index -1 结点的位置也就相当于找到了 index 结点的位置找到其位置很简单,cur 遍历链表 index-1 次即可
具体插入步骤:
1️⃣node.next = prevIndex.next;
2️⃣prevIndex.next = node;这两行不能交换位置❗️❗️❗️
如果先让 prevIndex.next = node;那么就会丢失 index 位置的那个结点↪️,此时 node.next = prevIndex.next 就相当于 node.next = node;代码会发生错误❌
注意还有一个特殊点当链表中无任何节点,为null时,无论index为何值,都会直接添加一个节点。
public void addIndex(int index,int a){if(head==null){ListNode listNode = new ListNode(a);head=listNode;return;}if(index<0||index>size()){System.out.println("位置不合法");//这里就不搞抛出异常了,我们简单点return;}if(index==0){addFirst(a);return;}if(index==size()){addLast(a);return;}ListNode listNode = new ListNode(a);ListNode cur=head;for (int i = 0; i <index-1 ; i++) {cur=cur.next;}listNode.next=cur.next;cur.next=listNode; }
contains——判定是否包含某个元素
比较简单,遍历这个数组即可
public void contain(int key){ListNode cur=head;while(cur!=null){if(cur.value==key){System.out.println(true);return;}cur=cur.next;}System.out.println(false); }因为这里我们存放的是 int 类型的变量,但 LinkedList 当中是存放引用数据类型的
⚠️⚠️⚠️当表中是引用类型时,就不可以用“等号”比较,应该用 equals 方法
remove——删除第一次出现关键字为key的结点
1️⃣如果链表为空就不能再删了
2️⃣如果头结点就是要删除的 key 结点,直接 head 存放下一个结点的地址
3️⃣如果链表其他结点是要删除的 key 结点,要先找到 key 结点的前一个结点
当 key 结点的前一个结点的 next 不再存放 key 结点地址时,key 结点此后不会再被使用,会被系统自动回收🗑️
所以完整代码如下:
public void remove(int key){ListNode cur=head;if(head==null) {System.out.println("为空链表,不能进行删除操作");return;}if(cur.value==key) {head=head.next;return;}while(cur.next!=null){if(cur.next.value==key){cur.next=cur.next.next;return;}cur=cur.next;}System.out.println("不存在该数"); }
removeAll——删除所有值为key的结点
这里我们将cur从head处开始检验:
当cur的下一个节点中的值等于key时: cur.next=cur.next.next,否则cur=cur.next。
最后检测完毕后还要看一下head处的值是否等于key,如果等于则将head=head.next。
完整代码如下:
public void removeAll(int key){if(this.head == null) {System.out.println("为空链表,不能进行删除操作");return;}ListNode cur = head;while(cur.next != null){if(cur.next.value == key){cur.next=cur.next.next;}else {cur = cur.next;}}if(head.value==key){head = head.next;}}
clear——清空单链表
head 这个变量一直存放着链表的头结点位置,把head置空,就找不到此链表,那么链表中的所有结点都会被系统自动回收🗑️
public void clear() {head = null;}
4.3完整代码及使用
完整代码
public class SingleLinkedList {static class ListNode{public int value;public ListNode next;public ListNode(int value) {this.value = value;}}public ListNode head;public void createList(){ListNode listNode1 = new ListNode(45);ListNode listNode2 = new ListNode(46);ListNode listNode3 = new ListNode(50);ListNode listNode4 = new ListNode(56);ListNode listNode5 = new ListNode(67);listNode1.next=listNode2;listNode2.next=listNode3;listNode3.next=listNode4;listNode4.next=listNode5;head=listNode1;}public void display(){ListNode cur=head;while(cur!=null){System.out.print(cur.value+" ");cur=cur.next;}System.out.println();}public int size(){int count=0;ListNode cur=head;while(cur!=null){cur=cur.next;count++;}return count;}
public void contain(int key){ListNode cur=head;while(cur!=null){if(cur.value==key){System.out.println(true);return;}cur=cur.next;}System.out.println(false);
}public void addFirst(int a){ListNode listNode = new ListNode(a);listNode.next=head;head=listNode;
}
public void addLast(int a){ListNode listNode = new ListNode(a);ListNode cur=head;if(head==null){head=listNode;return;
}while(cur.next!=null){cur=cur.next;}cur.next=listNode;
}public void addIndex(int index,int a){if(head==null){ListNode listNode = new ListNode(a);head=listNode;return;}if(index<0||index>size()){System.out.println("位置不合法");//这里就不搞抛出异常了,我们简单点return;}if(index==0){addFirst(a);return;}if(index==size()){addLast(a);return;}ListNode listNode = new ListNode(a);ListNode cur=head;for (int i = 0; i <index-1 ; i++) {cur=cur.next;}listNode.next=cur.next;cur.next=listNode;
}public void remove(int key){ListNode cur=head;if(head==null) {System.out.println("为空链表,不能进行删除操作");return;}if(cur.value==key) {head=head.next;return;}while(cur.next!=null){if(cur.next.value==key){cur.next=cur.next.next;return;}cur=cur.next;}System.out.println("不存在该数");
}public void removeAll(int key){if(this.head == null) {System.out.println("为空链表,不能进行删除操作");return;}ListNode cur = head;while(cur.next != null){if(cur.next.value == key){cur.next=cur.next.next;}else {cur = cur.next;}}if(head.value==key){head = head.next;}}public void clear(){head=null;}}
完整代码的使用
public class Test {public static void main(String[] args) {SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.createList();singleLinkedList.display();System.out.println(singleLinkedList.size());singleLinkedList.contain(45);singleLinkedList.addFirst(12);singleLinkedList.addLast(67);singleLinkedList.addIndex(3, 22);singleLinkedList.display();singleLinkedList.remove(22);singleLinkedList.remove(12);singleLinkedList.display();singleLinkedList.removeAll(67);singleLinkedList.display();System.out.println("=======================");singleLinkedList.clear();//清空该链表singleLinkedList.display();System.out.println("已清空该链表");System.out.println("=======================");}}

5.总结
所以,我们在本文中详细讲述了链表的概念和结构,并成功模拟了无头非循环单链表的实现。在下篇文章中,我们将带来一些关于单链表的面试题。在此,我们诚挚地邀请各位大佬们为我们点赞、关注,并在评论区留下您宝贵的意见与建议。让我们共同学习,共同进步,为知识的海洋增添更多宝贵的财富!🎉🎉🎉❤️❤️💕💕🥳👏👏👏

相关文章:
【Java数据结构】详解LinkedList与链表(一)
🔒文章目录: 1.❤️❤️前言~🥳🎉🎉🎉 2.ArrayList的缺陷 3.链表的概念及结构 4.无头单向非循环链表的实现 4.1成员属性 4.2成员方法 createList display——打印链表 addFirst——头插 addLast…...
PDF高效编辑器革新:一键智能转换PDF至HTML,轻松开启文件处理全新时代!
信息爆炸的时代,PDF文件因其跨平台、不易修改的特性,成为了商务、教育、出版等领域不可或缺的文件格式。然而,PDF文件的固定性也带来了诸多不便,特别是在需要对其内容进行编辑或格式转换时。这时,一款高效、易用的PDF编…...
JDBC知识
JDBC是什么? 这工作中我们针对数据库的操作,实际上很少会用到SQL语句,通过命令行/图形化来操作数据库,更多的是通过主流的编程语言来对数据库进行操作,即使通过代码来操作数据,我们还是会使用到SQL语句,所以掌握SQL语句也是很重要的. 如何通过代码操作数据库? 通过代码操作…...
C++操纵符用法
C中的操纵符(Manipulators)是用于格式化输入输出的特殊工具。它们可以在输出流中控制各种格式,如设置字段宽度、精度、填充字符等。以下是一些常用的操纵符及其用法: setw(int width): 设置字段宽度为width个字符。 cout <<…...
【一步一步了解Java系列】:子类继承以及代码块的初始化
看到这句话的时候证明:此刻你我都在努力 加油陌生人 个人主页:Gu Gu Study专栏:一步一步了解Java 喜欢的一句话: 常常会回顾努力的自己,所以要为自己的努力留下足迹 喜欢的话可以点个赞谢谢了。 作者:小闭 …...
探索Expect Python用法:深入解析与实战挑战
探索Expect Python用法:深入解析与实战挑战 在自动化和脚本编写领域,Expect Python已经成为了一种强大的工具组合。它结合了Expect的交互式会话处理能力和Python的编程灵活性,为开发者提供了一种全新的方式来处理复杂的自动化任务。然而&…...
【PostgreSQL17新特性之-explain命令新增选项】
EXPLAIN是一个用于显示语句执行计划的命令,可用于显示以下语句类型之一的执行计划: - SELECT - INSERT - UPDATE - DELETE - VALUES - EXECUTE - DECLARE - CREATE TABLE AS - CREATE MATERIALIZED VIEWPostgreSQL17-beta1版本近日发布了,新…...
JAVA实现人工智能,采用框架SpringAI
文章目录 JAVA实现人工智能,采用框架SpringAISpring AI介绍使用介绍项目前提项目结构第一种方式采用openai1. pom文件: 2. application.yml 配置3.controller 实现层 项目测试 JAVA实现人工智能,采用框架SpringAI Spring AI介绍 Spring AI是AI工程师的一个应用框架…...
基础—SQL—DQL(数据查询语言)分组查询
一、引言 分组查询的关键字是:GROUP BY。 二、DQL—分组查询 1、语法 SELECT 字段列表 FROM 表名 [ WHERE 条件 ] GROUP BY 分组字段名 [ HAVING 分组后过滤条件 ]; 注意: 1、[ ] 里的内容可以有可以没有。 2、这条SQL语句有两块指定条件的地方&#…...
从CSV到数据库(简易)
需求:客户上传CSV文档,要求CSV文档内容查重/插入/更新相关数据。 框架:jdbcTemplate、commons-io、 DB:oracle 相关依赖: 这里本来打算用的2.11.0,无奈正式项目那边用老版本1.3.1,新版本对类型…...
K210视觉识别模块学习笔记3:内存卡写入拍摄图片_LED三色灯的操作_按键操作_定时器的配置使用
今日开始学习K210视觉识别模块: LED三色灯的操作_按键操作_定时器的配置使用_内存卡写入拍摄图片 亚博智能的K210视觉识别模块...... 固件库版本: canmv_yahboom_v2.1.1.bin 本文最终目的是编写一个按键拍照的例程序: 为以后的专用场景的模型训练做准备…...
如何定义“智慧校园”这个概念
在信息爆炸的时代,教育面临着前所未有的挑战:如何让每个学生在海量知识中找到属于自己的路径?如何让教师的智慧与科技的力量相得益彰?如何让校园成为培养创新思维的摇篮?智慧校园,这一概念的提出࿰…...
OpenSSL自签名证书
文章目录 生成1. 生成根证书的私钥(root_private_key.pem)2. 创建根证书的CSR和自签名证书(root_csr.pem)3. 生成服务器证书的私钥(server_private_key.pem)4. 创建服务器证书的CSR(server_priv…...
QtCreator调试运行工程报错,无法找到相关库的的解决方案
最新在使用国产化平台做qt应用开发时,总是遇到qtcreator内调试运行 找不到动态库的问题,为什么会出现这种问题呢?明明编译的时候能够正常通过,运行或者调试的时候找不到相关的库呢?先说结论,排除库本身的问…...
【Python系列】Python 元组(Tuple)详解
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
特征融合篇 | YOLOv8 引入动态上采样模块 | 超过了其他上采样器
1. 介绍 本篇介绍了一种将动态上采样模块引入 YOLOv8 目标检测算法的新方法,该方法在 COCO 数据集上获得了 55.7% 的 mAP,超越了其他上采样器。该方法将动态上采样模块引入到 YOLOv8 的特征融合阶段,能够根据输入图像的特征分辨率动态调整上…...
Beyond Compare 3密钥被撤销的解决办法
首先,BCompare3的链接如下 链接:https://pan.baidu.com/s/1vuSxY0cVQCt0-8CpFzUhvg 提取码:8888 --来自百度网盘超级会员V7的分享 1.问题现象 激活之后在使用过程中有时候会出现密钥被撤销的警告,而且该工具无法使用ÿ…...
知识见闻 - 人和动物的主要区别
人类和动物的主要区别之一确实在于理性,但这只是众多区别中的一个方面。以下是一些更全面的比较,突出人类和动物之间的主要区别: 理性和抽象思维: 人类:人类具有高度发展的理性能力,可以进行抽象思维、逻辑…...
Javaweb基础之工程路径
大家好,这里是教授.F 引入: 工程路径有一个知识点需要注意:就是相对路径。所谓相对路径就是依赖当前位置: 相对路径的定位依赖于当前位置或参考位置。 使用相对路径来解决, 一个非常重要的规则:页面所有的…...
国际荐酒师(香港)协会受邀出席广州意大利国庆晚宴
2024年5月30日,意大利驻广州总领事馆举办的2024年意大利国庆招待会及晚宴,庆祝意大利共和国成立。此次晚宴旨在促进中意两国之间的文化交流与合作。国际荐酒师(香港)协会受主办方邀请参与了这一重要活动。 国际荐酒师(…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...







