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

6. LinkedList与链表

一、ArrayList的缺陷

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

二、链表

1. 链表的概念及结构

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

1.1 单向或者双向 

1.2 带头或者不带头

1.3 循环或者非循环

重点掌握两种:  

  • 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
  • 无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

2. 链表的实现

import java.util.List;public class MySingleLinkedList {static class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;//代表链表的头节点public void createList() {ListNode node1 = new ListNode(12);ListNode node2 = new ListNode(23);ListNode node3 = new ListNode(34);ListNode node4 = new ListNode(45);ListNode node5 = new ListNode(56);node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;this.head = node1;}public void display() {ListNode cur = head;while (cur != null) {System.out.print(cur.val+" ");cur = cur.next;}System.out.println();}/*** 从指定位置 newHead 开始打印链表* @param newHead*/public void display(ListNode newHead) {ListNode cur = newHead;while (cur != null) {System.out.print(cur.val+" ");cur = cur.next;}System.out.println();}public int size(){int count = 0;ListNode cur = head;while (cur != null) {count++;cur = cur.next;}return count;}public void addFirst(int val) {ListNode node = new ListNode(val);node.next = head;head = node;}public void addLast(int val) {ListNode node = new ListNode(val);if(head == null) {head = node;return;}ListNode cur = head;while (cur.next != null) {cur = cur.next;}cur.next = node;}public void addIndex(int index,int val) {//1.判断index的合法性try {checkIndex(index);}catch (IndexNotLegalException e) {e.printStackTrace();}//2.index == 0  || index == size()if(index == 0) {addFirst(val);return;}if(index == size()) {addLast(val);return;}//3. 找到index的前一个位置ListNode cur = findIndexSubOne(index);//4. 进行连接ListNode node = new ListNode(val);node.next = cur.next;cur.next = node;}private ListNode findIndexSubOne(int index) {int count = 0;ListNode cur = head;while (count != index-1) {cur = cur.next;count++;}return cur;}private void checkIndex(int index) throws IndexNotLegalException{if(index < 0 || index > size()) {throw new IndexNotLegalException("index不合法");}}public boolean contains(int val) {ListNode cur = head;while (cur != null) {if(cur.val == val) {return true;}cur = cur.next;}return false;}public void remove(int val) {if(head == null) {return;}if(head.val == val) {head = head.next;return;}ListNode cur = head;while (cur.next != null) {if(cur.next.val == val) {ListNode del = cur.next;cur.next = del.next;return;}cur = cur.next;}}public void removeAllKey(int val) {//1. 判空if(this.head == null) {return;}//2. 定义prev 和 curListNode prev = head;ListNode cur = head.next;//3.开始判断并且删除while(cur != null) {if(cur.val == val) {prev.next = cur.next;//cur = cur.next;}else {prev = cur;//prev = prev.next;//cur = cur.next;}cur = cur.next;}//4.处理头节点if(head.val == val) {head = head.next;}}public void clear() {//head = null;ListNode cur = head;while (cur != null) {ListNode curN = cur.next;//cur.val = null;cur.next = null;cur = curN;}head = null;}
}

三、链表面试题

1. 删除链表中等于给定值 val 的所有节点。

2. 反转一个单链表。

3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

4. 输入一个链表,返回该链表中倒数第k个结点。

5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前。

7. 链表的回文结构。

8. 输入两个链表,找出它们的第一个公共结点。

9. 给定一个链表,判断链表中是否有环。

10. 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL。

四、LinkedList的模拟实现

public class MyLinkedList {static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public ListNode last;//头插法public void addFirst(int data){ListNode node = new ListNode(data);if(head == null) {head = node;last = node;//return;}else {node.next = head;head.prev = node;head = node;}}//尾插法public void addLast(int data){ListNode node = new ListNode(data);if(head == null) {head = last = node;}else {last.next = node;node.prev = last;last = node;}}//任意位置插入,第一个数据节点为0号下标public void addIndex(int index,int data){if(index < 0 || index > size()) {return;}if(index == 0) {addFirst(data);return;}if(index == size()) {addLast(data);return;}ListNode cur = searchIndex(index);ListNode node = new ListNode(data);node.next = cur;cur.prev.next = node;node.prev = cur.prev;cur.prev = node;}private ListNode searchIndex(int index) {ListNode cur = head;int count = 0;while (count != index) {cur = cur.next;count++;}return cur;}//查找是否包含关键字key是否在单链表当中public boolean contains(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {return true;}cur =cur.next;}return false;}//得到单链表的长度public int size(){int count = 0;ListNode cur = head;while (cur != null) {count++;cur =cur.next;}return count;}public void display(){ListNode cur = head;while (cur != null) {System.out.print(cur.val+" ");cur =cur.next;}System.out.println();}//删除第一次出现关键字为key的节点public void remove(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {if(cur == head) {head = head.next;//判断 头节点是不是1个if(head != null) {head.prev = null;}else {last = null;}}else {cur.prev.next = cur.next;if(cur.next == null) {//cur.prev.next = cur.next;last = cur.prev;}else {//cur.prev.next = cur.next;cur.next.prev = cur.prev;}}return;}else {cur = cur.next;}}}//删除所有值为key的节点public void removeAllKey(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {if(cur == head) {head = head.next;//判断 头节点是不是1个if(head != null) {head.prev = null;}else {last = null;}}else {cur.prev.next = cur.next;if(cur.next == null) {//cur.prev.next = cur.next;last = cur.prev;}else {//cur.prev.next = cur.next;cur.next.prev = cur.prev;}}}cur = cur.next;}}public void clear(){ListNode cur = head;while (cur != null) {ListNode curN = cur.next;cur.next = null;cur.prev = null;cur = curN;}head = null;last = null;}}

五、LinkedList的使用

1. 什么是LinkedList

LinkedList的底层是双向链表结构(链表后面介绍),由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

在集合框架中,LinkedList也实现了List接口,具体如下:

【说明】

  1. LinkedList实现了List接口
  2. LinkedList的底层使用了双向链表
  3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
  4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
  5. LinkedList比较适合任意位置插入的场景

2. LinkedList的使用

2.1 LinkedList的构造

public static void main(String[] args) {// 构造一个空的LinkedListList<Integer> list1 = new LinkedList<>();List<String> list2 = new java.util.ArrayList<>();list2.add("JavaSE");list2.add("JavaWeb");list2.add("JavaEE");// 使用ArrayList构造LinkedListList<String> list3 = new LinkedList<>(list2);
}
2.2 LinkedList的其他常用方法介绍

2.3 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);list.add(5);list.add(6);list.add(7);list.add(8);System.out.println(list.size());//foreach遍历for (int e:list) {System.out.print(e + ", ");  // 1, 2, 3, 4, 5, 6, 7, 8, }System.out.println();//使用迭代器遍历——正向遍历ListIterator<Integer> it = list.listIterator();while (it.hasNext()){System.out.print(it.next() + ", ");  // 1, 2, 3, 4, 5, 6, 7, 8, }System.out.println();//使用反向迭代器——反向遍历ListIterator<Integer> rit = list.listIterator(list.size());while (rit.hasPrevious()){System.out.print(rit.previous() + ", ");  // 8, 7, 6, 5, 4, 3, 2, 1, }System.out.println();}
}

六、ArrayList和LinkedList的区别

相关文章:

6. LinkedList与链表

一、ArrayList的缺陷 通过源码知道&#xff0c;ArrayList底层使用数组来存储元素&#xff0c;由于其底层是一段连续空间&#xff0c;当在ArrayList任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往前或者往后搬移&#xff0c;时间复杂度为O(n)&#xff0c;效率比…...

Statcounter Global Stats 提供全球统计数据信息

Statcounter Global Stats 提供全球统计数据信息 1. Statcounter Global Stats2. Mobile & Tablet Android Version Market Share WorldwideReferences Statcounter Global Stats https://gs.statcounter.com/ Statcounter Global Stats are brought to you by Statcounte…...

Linux kernel中的dts dtsi dtb dtc dtb.img dtbo.img

1、问题 kernel与hsm会设置一些gpio&#xff0c;但是某些gpio会在kernel与hsm侧共同设置&#xff0c;导致最终的设置结果失败&#xff0c;将kernel侧在dts文件中设置的gpio注释掉之后&#xff0c;发现hsm设置gpio时还是失败 2、问题原因 因为dts文件不仅仅会影响kernel镜像&…...

微信小程序页面制作——个人信息

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

使用C++11的`std::async`执行异步任务:实战指南

使用C11的std::async执行异步任务&#xff1a;实战指南 在现代软件开发中&#xff0c;异步编程是提高应用程序性能和响应速度的重要手段。C11引入了std::async&#xff0c;使得编写异步任务变得更加简单和直观。本文将详细介绍如何使用std::async执行异步任务&#xff0c;并提…...

【高阶数据结构】B树、B+树、B*树

B树、B树、B*树 1. 常见的搜索结构2. B树概念3. B树的插入分析4. B树的插入实现4.1 B树的节点设计4.2 B树的部分插入实现14.3 B树的查找4.4 B树的部分插入实现24.5 插入key的过程4.7 B树的插入完整代码4.8 B树的简单验证4.9 B树的删除4.10 B树的性能分析 5. B树6. B*树7. 总结8…...

HBuilderx中vue页面引用scss样式

scss为css样式的预编译器&#xff0c;引入了变量、嵌入、混合、集成、引入等功能&#xff0c;相对于css样式&#xff0c;实现了样式的编程&#xff0c;具有更灵活的样式编写模式。 那么在HBuilderx中&#xff0c;“.vue”格式页面如何调用scss样式呢&#xff1f;详细如下&#…...

粒子群算法原理的示例介绍

一&#xff1a;粒子群优化算法的介绍 粒子群优化算法&#xff08;PSO&#xff09;是一种基于群体智能的优化算法&#xff0c;于1995年提出。它受到鸟群狩猎行为的启发&#xff0c;通过模拟鸟群或鱼群的社会行为来进行问题的求解。 基本原理 粒子群算法中&#xff0c;每个解决…...

GNU/Linux - Open函数使用的O_CLOEXEC flag

在 Linux 中&#xff0c;“O_CLOEXEC ”标志与 “open ”系统调用一起使用&#xff0c;用于指定在使用 “exec ”系列函数&#xff08;如 “execve”、“execl ”等&#xff09;执行新程序时&#xff0c;“open ”返回的文件描述符应自动关闭。 In Linux, the O_CLOEXEC flag i…...

AWQ量化(Activation-aware Weight Quantization)

论文&#xff1a; AWQ: Activation-aware Weight Quantization for On-Device LLM Compression and Acceleration 中文解读&#xff1a; 深入理解AWQ量化技术 - 知乎 (zhihu.com) 动机&#xff1a;端侧设备用LLM&#xff0c;为了减少显存占用量&#xff0c;所以要用INT4量化&am…...

SprinBoot+Vue体育商品推荐的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…...

【Python基础】Python函数

本文收录于 《Python编程入门》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程基础知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、函数的定义与调用三、函数参数3.1 位置参数3.2 默认参数3.3 可变数量参数&#xff08;或不定长参数…...

【超简单】1分钟解决ppt全文字体一键设置

省流 ppt的全部字体需要在“幻灯片母版”里面&#xff0c;“自定义字体”去设置好标题与正文的字体之后才算全部设置完毕 “视图”---“幻灯片母版” 找到“字体”---“自定义字体” 设置好中文和西文的字体&#xff0c;都可以按照自己的选择来&#xff0c;保存即可 吐槽 之…...

数组与贪心算法——179、56、57、228(2简2中)

179. 最大数&#xff08;简单&#xff09; 给定一组非负整数 nums&#xff0c;重新排列每个数的顺序&#xff08;每个数不可拆分&#xff09;使之组成一个最大的整数。 注意&#xff1a;输出结果可能非常大&#xff0c;所以你需要返回一个字符串而不是整数。 解法一、自定义比较…...

WireShark过滤器

文章目录 一、WireShark过滤器概念1. 捕获过滤器&#xff08;Capture Filters&#xff09;2. 显示过滤器&#xff08;Display Filters&#xff09;3. 捕获过滤器与显示过滤器的区别4. 过滤器语法结构实际应用场景 二、WireShark捕获数据包列表1. **No.&#xff08;序号&#xf…...

2024年全新deepfacelive如何对应使用直播伴侣-腾讯会议等第三方软件

# 2024年全新deepfacelive如何对应使用直播伴侣-腾讯会议等第三方软件 前提按照之前的步骤打开deepfacelive正确配置并且在窗口已经输出了换脸后的视频&#xff0c;不懂步骤可以移步 https://doc.youyacao.com/88/2225 ## 首先下载obs并配置 https://obsproject.com/ 通过…...

告别懵逼——前端项目调试与问题排查方法小结

在日常工作中&#xff0c;我们常常会遇到以下两类典型的挑战&#xff1a; 场景一&#xff1a; 接手无文档的老项目 1、情景描述&#xff1a; 你接手了一个历史久远的项目&#xff0c;项目文档缺失&#xff0c;前任开发者已经离开&#xff0c;而你对当前的业务逻辑和代码结构都…...

[数据集][目标检测]肺炎检测数据集VOC+YOLO格式4983张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4983 标注数量(xml文件个数)&#xff1a;4983 标注数量(txt文件个数)&#xff1a;4983 标注…...

顶层const和底层const

在C中&#xff0c;const修饰符用于声明常量&#xff0c;有两种常见的形式&#xff1a;顶层const和底层const&#xff0c;它们之间的区别在于它们修饰的对象及其在不同场景中的作用。 1. 顶层const (Top-level const) 顶层const用于修饰变量本身&#xff0c;使其成为常量。这意…...

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建 首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...