Java中的链表

文章目录

  • 前言
  • 一、链表的概念及结构
  • 二、单向不带头非循坏链表的实现
    • 2.1打印链表
    • 2.2求链表的长度
    • 2.3头插法
    • 2.4尾插法
    • 2.5任意位置插入
    • 2.6查找是否包含某个元素的节点
    • 2.7删除第一次出现这个元素的节点
    • 2.8删除包含这个元素的所以节点
    • 2.9清空链表
    • 单向链表的测试
  • 三、双向不带头非循坏链表的实现
    • 3.1打印双向链表
    • 3.2求双向链表的长度
    • 3.3头插法
    • 3.4尾插法
    • 3.5任意位置插入
    • 3.6查找是否包含某个元素的节点
    • 3.7删除第一次出现这个元素的节点
    • 3.7删除包含这个元素的所有节点
    • 3.9清空双向链表
    • 双向链表的测试
    • LinkedList的遍历方式
    • 四、ArrayList和LinkedList的区别


前言

在前面我们已经学习了关于顺序表ArrayList的一些基本操作。通过源码知道,ArrayList底层使用数组来存储元素,由于其底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。因此:java集合中又引入了LinkedList,即链表结构


一、链表的概念及结构

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的
注意:
1.链式结构在逻辑上是连续的,但是在物理上不一定连续
2.现实中的结点一般都是从堆上申请出来的
3.从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可能是连续,也可能不连续

链表的结构有8种样式:
单向带头循坏、单向带头非循坏、单向不带头循坏、单向不带头非循坏
双向带头循坏、双向带头非循坏、双向不带头循坏、双向不带头非循坏

这里我们主要学习以下两中结构:
单向不带头非循坏
在这里插入图片描述
LinkedList底层使用的就是双向不带头非循坏
在这里插入图片描述

二、单向不带头非循坏链表的实现

2.1打印链表

不带参数的打印

public void display() {ListNode cur = head;if(cur != null) {//遍历完所以节点System.out.print(cur.val+" ");cur = cur.next;}System.out.println();
}

带参数的打印

public void display(ListNode newHead) {ListNode cur = newHead;if(cur != null) {System.out.print(cur.val+" ");cur = cur.next;}System.out.println();
}    

2.2求链表的长度

public int size(){ListNode cur = head;int count = 0;while (cur != null) {count++;cur = cur.next;}return count;
}    

2.3头插法

public void addFirst(int data){ListNode node = new ListNode(data);node.next = head;head = node;
}

2.4尾插法

public 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;}
}

2.5任意位置插入

在任意位置插入时我们要判断该位置是否合法,不合法的时候要抛一个异常

  public void addIndex(int index,int data){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 = serchIndex(index);node.next = cur.next;cur.next = node;
}    

找要添加节点位置的前一个节点

public ListNode serchIndex(int index) {ListNode cur = head;int count = 0;while (count != index-1) {cur = cur.next;count++;}return cur;
}    

2.6查找是否包含某个元素的节点

遍历这个链表找是否与这个元素相同

public boolean contains(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {return true;}cur = cur.next;}return false;
}    

2.7删除第一次出现这个元素的节点

public void remove(int key){if(head == null) {return;}if(head.val == key) {head = head.next;return;}ListNode cur = findKey(key);if(cur == null) {return;//没有要删除的元素}ListNode del = cur.next;cur.next = del.next;
}    

要删除节点的前一个节点

public ListNode findKey(int key) {ListNode cur = head;while (cur.next != null) {if(cur.next.val == key) {return cur;}else {cur = cur.next;}}return null;
}    

2.8删除包含这个元素的所以节点

public 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;}
}    

2.9清空链表

清空链表只需要把头节点置为空

public void clear() {head = null;
}    

单向链表的测试

public class Test {public static void main(String[] args) {MySingleList list = new MySingleList();list.addLast(30);//尾插list.addLast(20);list.addLast(30);list.addLast(40);list.addLast(50);list.addFirst(100);//头插list.addIndex(2,15);//任意位置插入list.display();System.out.println("*****");System.out.println(list.contains(20));//查看是否包含某个节点System.out.println("*****");System.out.println(list.size());//求链表长度System.out.println("*****");list.remove(30);//删除第一个出现的节点list.display();list.removeAllKey(30);//删除包含这个元素的所以节点System.out.println("*****");list.display();System.out.println("*****");list.clear();//清空链表list.display();}
}

在这里插入图片描述

三、双向不带头非循坏链表的实现

3.1打印双向链表

public void display(){ListNode cur = head;while (cur != null) {System.out.print(cur.val+" ");cur = cur.next;}System.out.println();
}    

3.2求双向链表的长度

public int size(){int count = 0;ListNode cur = head;while (cur != null) {count++;cur = cur.next;}return count;
}    

3.3头插法

public void addFist(int data) {ListNode node = new ListNode(data);if(head == null) {//一个节点都没有的情况head = node;last = node;}else {node.next = head;head.prev = node;head = node;}
}    

3.4尾插法

public void addLast(int data) {ListNode node = new ListNode(data);if(head == null) {//一个节点都没有的情况head = node;last = node;}else {last.next = node;node.prev = last;last = node;}
}    

3.5任意位置插入

这里的插入与单向链表一样也需要判断该位置的合法性,不合法时抛一个异常

public void addIndex(int index,int data) {if(index < 0 || index > size()) {throw new IndexException("双向链表中index的位置不合法:"+index);}if(index == 0) {addFist(data);}if(index == size()) {addLast(data);}ListNode cur = findIndex(index);ListNode node = new ListNode(data);node.next = cur;cur.prev.next = node;node.prev = cur.prev;cur.prev = node;
}    

要添加节点的位置

public ListNode findIndex(int index) {ListNode cur = head;if(index != 0) {cur = cur.next;index --;}return cur;
}    

3.6查找是否包含某个元素的节点

public boolean contains(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {return true;}cur = cur.next;}return false;
}    

3.7删除第一次出现这个元素的节点

因为数据结构是一门逻辑性非常严谨的学科,所以这里的删除需要考虑多种因素

public void remove(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {if(cur == head) {head = head.next;if (head != null) {head.prev = null;}else {//只有一个节点,而且是需要删除的节点last = null;}}else {//删除中间节点if(cur.next != null) {cur.next.prev = cur.prev;cur.prev.next = cur.next;}else {//删除尾巴节点cur.prev.next = cur.next;last = last.prev;}}return;}cur = cur.next;}
}    

3.7删除包含这个元素的所有节点

public void remove(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {if(cur == head) {head = head.next;if (head != null) {head.prev = null;}else {//只有一个节点,而且是需要删除的节点last = null;}}else {//删除中间节点if(cur.next != null) {cur.next.prev = cur.prev;cur.prev.next = cur.next;}else {//删除尾巴节点cur.prev.next = cur.next;last = last.prev;}}}cur = cur.next;}
}    

3.9清空双向链表

public void clear(){ListNode cur = head;while (cur != null) {ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = cur.next;}head = null;//头节点置空last = null;//尾巴节点置空
}    

双向链表的测试

public class Test {public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addLast(12);//尾插法myLinkedList.addLast(45);myLinkedList.addLast(34);myLinkedList.addLast(45);myLinkedList.addFist(56);//头插法myLinkedList.addIndex(2,15);//任意位置插入myLinkedList.display();System.out.println(myLinkedList.size());//求双向链表的长度System.out.println("******");System.out.println(myLinkedList.contains(23));//查找是否包含某个元素的节点System.out.println("******");myLinkedList.remove(45);//删除第一次出现这个元素的节点myLinkedList.display();System.out.println("******");myLinkedList.removeAllKey(45);//删除包含这个元素的所以节点myLinkedList.display();System.out.println("******");myLinkedList.clear();//清空链表myLinkedList.display();}
}

在这里插入图片描述

LinkedList的遍历方式

关于LinkedList的遍历方式有四种:

public class Test {public static void main(String[] args) {LinkedList<Integer> list = new LinkedList<>();list.add(1);list.add(2);list.add(3);list.add(4);System.out.println(list);//for循坏遍历for (int i = 0; i < list.size(); i++) {System.out.print(list.get(i)+" ");}System.out.println();System.out.println("*******");//foreach遍历for (int m : list) {System.out.print(m +" ");}System.out.println();System.out.println("*******");//使用迭代器——正向遍历ListIterator<Integer> it = list.listIterator();while (it.hasNext()) {System.out.print(it.next()+" ");}System.out.println();System.out.println("*******");//使用迭代器——反向遍历ListIterator<Integer> it2 = list.listIterator(list.size());while (it2.hasPrevious()) {System.out.print(it2.previous()+" ");}System.out.println();}
}    

在这里插入图片描述

四、ArrayList和LinkedList的区别

1.ArrayList在物理上是连续的,LinkedList在逻辑上连续,但在物理上不一定连续
2.ArrayList和LinkedList是两种不同的数据结构。ArrayList是基于动态数组的,而LinkedList则是基于链表的
3.当需要随机访问元素(如get和set操作)时,ArrayList效率更高,因为LinkedList需要逐个查找。但当进行数据的增加和删除操作(如add和remove操作)时,LinkedList效率更高,因为ArrayList在进行这些操作时需要移动大量数据
4.ArrayList需要手动设置固定大小的容量,使用方便但自由性低;而LinkedList能够随数据量变化而动态调整,自由性较高但使用较为复杂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/222321.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python】人工智能-机器学习——不调库手撕深度网络分类问题

1. 作业内容描述 1.1 背景 数据集大小150该数据有4个属性&#xff0c;分别如下 Sepal.Length&#xff1a;花萼长度(cm)Sepal.Width&#xff1a;花萼宽度单位(cm)Petal.Length&#xff1a;花瓣长度(cm)Petal.Width&#xff1a;花瓣宽度(cm)category&#xff1a;类别&#xff0…

【STM32】STM32学习笔记-GPIO输入(07)

00. 目录 文章目录 00. 目录01. 按键简介02. 传感器模块简介03. 光敏电阻传感器04. 按键电路图05. C语言数据类型06. C语言宏定义07. C语言typedef08. C语言结构体09. C语言枚举10. 附录 01. 按键简介 按键&#xff1a;常见的输入设备&#xff0c;按下导通&#xff0c;松手断开…

TCP/IP详解——ARP 协议

文章目录 一、ARP 协议1. ARP 数据包格式2. ARP 工作过程3. ARP 缓存4. ARP 请求5. ARP 响应6. ARP 代理7. ARP 探测IP冲突8. ARP 协议抓包分析9. ARP 断网攻击10. 总结 一、ARP 协议 ARP&#xff08;Address Resolution Protocol&#xff09;协议工作在网络层和数据链路层之间…

CCF编程能力等级认证GESP—C++2级—20230923

CCF编程能力等级认证GESP—C2级—20230923 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)⼩杨的 X 字矩阵数字⿊洞 答案及解析单选题判断题编程题1编程题…

使用Docker本地安装部署Draw.io绘图工具并实现远程访问协作办公

前言 提到流程图&#xff0c;大家第一时间可能会想到Visio&#xff0c;不可否认&#xff0c;VIsio确实是功能强大&#xff0c;但是软件为收费&#xff0c;并且因为其功能强大&#xff0c;导致安装需要很多的系统内存&#xff0c;并且是不可跨平台使用。所以&#xff0c;今天给…

电脑开机出现:CLIENT MAD ADDR (网卡启动系统)的解决办法

文章目录 前言步骤1、确定情况2、对症下药——关闭网卡启动 补充1、关于BIOS2、关于PXE 前言 最近给旧电脑重装系统安了下开发环境和常用软件啥的&#xff0c;之前还好好启动的电脑&#xff0c;开机突然需要额外加载一个页面&#xff0c;虽然最后正常启动了不影响使用&#xf…

Qt5 CMake环境配置

Qt5 CMake环境配置 设置Qt路径 有两种方法 Qt5_DIR&#xff0c;使用这个变量&#xff0c;必须把路径设置到Qt5Config.cmake所在文件夹&#xff0c;也就是安装目录下的lib/cmake/Qt5CMAKE_PREFIX_PATH&#xff0c;只需要设置到安装目录就可以了&#xff0c;这个目录就是bin、…

OpenStack和Docker结合?为何现在流行?

为何现在流行OpenStack和Docker结合&#xff1f; 结合的好处 1、资源管理与调度灵活&#xff1a; OpenStack提供了完善的虚拟机管理能力&#xff0c;而Kubernetes&#xff08;使用Docker作为容器运行环境&#xff09;在容器调度方面非常高效。将两者结合&#xff0c;可以实现…

RNN介绍及Pytorch源码解析

介绍一下RNN模型的结构以及源码&#xff0c;用作自己复习的材料。 RNN模型所对应的源码在&#xff1a;\PyTorch\Lib\site-packages\torch\nn\modules\RNN.py文件中。 RNN的模型图如下&#xff1a; 源码注释中写道&#xff0c;RNN的数学公式&#xff1a; 表示在时刻的隐藏状态…

ES6学习(三):Set和Map容器的使用

Set容器 set的结构类似于数组,但是成员是唯一且不会重复的。 创建的时候需要使用new Set([])的方法 创建Set格式数据 let set1 new Set([])console.log(set1, set1)let set2 new Set([1, 2, 3, 4, 5])console.log(set2, set2) 对比看看Set中唯一 let set3 new Set([1, 1,…

多架构容器镜像构建实战

最近在一个国产化项目中遇到了这样一个场景&#xff0c;在同一个 Kubernetes 集群中的节点是混合架构的&#xff0c;也就是说&#xff0c;其中某些节点的 CPU 架构是 x86 的&#xff0c;而另一些节点是 ARM 的。为了让我们的镜像在这样的环境下运行&#xff0c;一种最简单的做法…

Rust语言基础语法使用

1.安装开发工具: RustRover JetBrains: Essential tools for software developers and teams 下载: RustRover: Rust IDE by JetBrains 下载成功后安装并启动RustRover 安装中文语言包插件 重启RustRover生效

vue3引入echarts正确姿势

echarts文档地址&#xff1a; echarts官网地址 echarts配置手册 echarts 模板地址 1、安装 &#xff08;1&#xff09;安装echarts包 npm install echarts --save 或者 cnpm install echarts --save&#xff08;2&#xff09;安装vue echarts工具包 npm install echart…

持续集成交付CICD:Jenkins使用基于SaltStack的CD流水线下载Nexus制品

目录 一、理论 1.salt常用命令 二、实验 1.SaltStack环境检查 2.Jenkins使用基于SaltStack的CD流水线下载Nexus制品 二、问题 1.salt未找到命令 2.salt简单测试报错 3. wget输出日志过长 一、理论 1.salt常用命令 &#xff08;1&#xff09;salt 命令 该 命令执行s…

蓝牙物联网智慧物业解决方案

蓝牙物联网智慧物业解决方案是一种利用蓝牙技术来提高物业管理和服务效率的解决方案。它通过将蓝牙技术与其他智能设备、应用程序和云服务相结合&#xff0c;为物业管理和服务提供更便捷、高效和智能化的支持。 蓝牙物联网智慧物业解决方案包括&#xff1a; 1、设备管理&#…

JupyterNotebook安装依赖 使用conda环境

怎么使用JupyterNotebook安装依赖&#xff1f;&#xff08;使用conda环境&#xff1f;&#xff09; 预装的jupyter中有conda&#xff0c;可以进入终端执行相关命令 预装的Jupyter&#xff0c;目标用户是轻度的Jupyter用户&#xff0c;如果想使用conda的多环境等高级功能&#x…

Unity中的ShaderToy

文章目录 前言一、ShaderToy网站二、ShaderToy基本框架1、我们可以在ShaderToy网站中&#xff0c;这样看用到的GLSL文档2、void mainImage 是我们的程序入口&#xff0c;类似于片断着色器3、fragColor作为输出变量&#xff0c;为屏幕每一像素的颜色&#xff0c;alpha一般赋值为…

微信小程序单图上传和多图上传

图片上传主要用到 1、wx.chooseImage(Object object) 从本地相册选择图片或使用相机拍照。 参数 Object object 属性类型默认值必填说明countnumber9否最多可以选择的图片张数sizeTypeArray.<string>[original, compressed]否所选的图片的尺寸sourceTypeArray.<s…

从开源项目中学习如何自定义 Spring Boot Starter 小组件

前言 今天参考的开源组件Graceful Response——Spring Boot接口优雅响应处理器。 具体用法可以参考github以及官方文档。 基本使用 引入Graceful Response组件 项目中直接引入如下maven依赖&#xff0c;即可使用其相关功能。 <dependency><groupId>com.feiniaoji…

螺旋矩阵算法(leetcode第59题)

题目描述&#xff1a; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。示例 1&#xff1a;输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]] 示例 2&#xff1a;输入&#…