Java数据结构LinkedList单链表和双链表模拟实现及相关OJ题秒AC总结知识点
本篇文章主要讲述LinkedList链表中从初识到深入相关总结,常见OJ题秒AC,望各位大佬喜欢
一、单链表
1.1链表的概念及结构
1.2无头单向非循环链表模拟实现
1.3测试模拟代码
1.4链表相关面试OJ题
1.4.1 删除链表中等于给定值 val 的所有节点
1.4.2 反转一个单链表
1.4.3 给你单链表的头结点 head ,请你找出并返回链表的中间结点
1.4.4 输入一个链表,输出该链表中倒数第k个结点
1.4.5 合并俩个有序链表
二、双链表
2.1双向链表模拟实现
2.2LinkedList其他常用方法介绍
2.3ArrayList和LinkedList的区别
1.1链表的概念及结构
由于顺序表ArrayList不适合从任意位置插入或者删除元素,因此引入了LinkedList链表,链表是一种物理存储结构上非连续存储结构,也称链式存储,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
1. 单向或者双向
2. 带头或者不带头

3. 循环或者非循环

4.无头单向非循环链表或者无头双向链表
在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。
1.2无头单向非循环链表模拟实现
public class MySingleList {static class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public void createLink() {ListNode node1 = new ListNode(12);ListNode node2 = new ListNode(13);ListNode node3 = new ListNode(14);ListNode node4 = new ListNode(16);node1.next = node2;node2.next = node3;node3.next = node4;head = node1;}/*** @author 徐延焜xyk* @Description://遍历链表*/public void display() {ListNode cur = head;while (cur != null) {System.out.println(cur.val + " ");cur = cur.next;}System.out.println();}/*** @author 徐延焜xyk* @Description://查找是否包含关键字key是否在单链表当中*/public boolean contains(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}/*** @author 徐延焜xyk* @Description://得到单链表的长度 O(N)*/public int size() {int count = 0;ListNode cur = head;while (cur != null) {count++;cur = cur.next;}return count;}/*** @author 徐延焜xyk* @Description://头插法 O(1)*/public void addFirst(int data) {ListNode node = new ListNode(data);node.next = head;head = node;}/*** @author 徐延焜xyk* @Description://尾插法 O(N) 找尾巴的过程*/public void addLast(int data) {ListNode node = new ListNode(data);if (head == null) {head = node;return;}ListNode cur = head;while (cur.next != null) {cur = cur.next;}cur.next = node;}/*** @author 徐延焜xyk* @Description: //任意位置插入,第一个数据节点为0号下标*/public void addIndex(int index, int data) throws ListIndexOutofException {checkIndex(index);if (index == 0) {addFirst(data);return;}if (index == size()) {addFirst(data);return;}ListNode cur = findIndexSubOne(index);ListNode node = new ListNode(data);node.next = cur.next;cur.next = node;}/*** @author 徐延焜xyk* @Description:找到 index-1位置的节点的地址*/private ListNode findIndexSubOne(int index) {ListNode cur = head;int count = 0;while (count != index - 1) {cur = cur.next;count++;}return cur;}private void checkIndex(int index) throws ListIndexOutofException {if (index < 0 || index > size()) {throw new ListIndexOutofException("index位置不合法!");}}/*** @author 徐延焜xyk* @Description://删除第一次出现关键字为key的节点 O(N)*/public void remove(int key) {if (head == null) {return;}if (head.val == key) {head = head.next;return;}ListNode cur = searchPrev(key);if (cur == null) {return;}ListNode del = cur.next;cur.next = del.next;}/*** @author 徐延焜xyk* @Description:找到关键字key的前一个节点*/private ListNode searchPrev(int key) {ListNode cur = head;while (cur.next != null) {if (cur.next.val == key) {return cur;}cur = cur.next;}return null;}/*** @author 徐延焜xyk* @Description://删除所有值为key的节点*/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;}}}/*** @author 徐延焜xyk* @Description:保证链表当中 所有的节点 都可以被回收*/public void clear() {head = null;}
}
1.3测试模拟代码
public static void main(String[] args) {MySingleList mySingleList = new MySingleList();//LinkedList<Integer> stack = new LinkedList<Integer>();//Queue<MySingleList.ListNode> queue = new ArrayDeque<>();mySingleList.display();System.out.println("=======");System.out.println(mySingleList.contains(90));System.out.println(mySingleList.size());System.out.println("====测试插入===");mySingleList.addLast(1);mySingleList.addLast(2);mySingleList.addLast(3);mySingleList.addLast(4);try {mySingleList.addIndex(0,1);}catch (ListIndexOutofException e) {e.printStackTrace();}mySingleList.display();System.out.println("=============");mySingleList.removeAllKey(1);mySingleList.display();}


1.4链表相关面试OJ题
1.4.1 删除链表中等于给定值 val 的所有节点
1. 删除链表中等于给定值 val 的所有节点。
203. 移除链表元素 - 力扣(LeetCode)

class Solution {public ListNode removeElements(ListNode head, int val) {if (head == null){return null;}ListNode prev = head;ListNode cur = head.next;while (cur != null){if (cur.val == val){prev.next = cur.next;cur = cur.next;}else{prev = cur;cur = cur.next;}}if (head.val == val){head = head.next;}return head;}
}
1.4.2 反转一个单链表
给你单链表的头节点
head,请你反转链表,并返回反转后的链表。206. 反转链表 - 力扣(LeetCode)
class Solution {public ListNode reverseList(ListNode head) {if(head == null){return null;}if(head.next == null){return head;}ListNode cur = head.next;head.next = null;while(cur != null){ListNode curNext = cur.next;cur.next = head;head = cur;cur = curNext;}return head;}
}
1.4.3 给你单链表的头结点 head ,请你找出并返回链表的中间结点
给你单链表的头结点
head,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
876. 链表的中间结点 - 力扣(LeetCode)
class Solution {public ListNode middleNode(ListNode head) {ListNode fast = head;ListNode slow = head;while (fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;}return slow;}
}
1.4.4 输入一个链表,输出该链表中倒数第k个结点
链表中倒数第k个结点_牛客题霸_牛客网 (nowcoder.com)
仅仅用一个指针进行遍历注定是没有办法很优美地实现此问题解答的,所以要用两个指针,这两个指针的位置相差k-1个距离,当快指针走到最后一个节点的时候,慢指针指向的位置就是我们要的倒数第k个节点了。思想就是这么简单了,很多链表类的题目都是活用指针就可以解决的,一个指针不可以的时候就两个指针来完成。
public class Solution {public ListNode FindKthToTail(ListNode head, int k) {if (k <= 0 || head == null) {return null;}ListNode fast = head;ListNode slow = head;while (k - 1 != 0) {fast = fast.next;if (fast == null) {return null;}k--;}while (fast.next != null) {fast = fast.next;slow = slow.next;}return slow;}
}
1.4.5 合并俩个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
21. 合并两个有序链表 - 力扣(LeetCode)
class Solution {public ListNode mergeTwoLists(ListNode head1, ListNode head2) {ListNode newHead = new ListNode(0);ListNode tmp = newHead;while (head1 != null && head2 != null){if (head1.val < head2.val){tmp.next = head1;head1 = head1.next;tmp = tmp.next;}else {tmp.next = head2;head2 = head2.next;tmp = tmp.next;}}if (head1 != null){tmp.next = head1;}if (head2 != null){tmp.next = head2;}return newHead.next;}
}
上述这些oj题都是最基本的题目,请关注后续播客会有难度题上线!!
二、双链表
2.1双向链表模拟实现
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;//头插法O(1)public void addFirst(int data) {ListNode node = new ListNode(data);if (head == null) {head = node;last = node;} else {node.next = head;head.prev = node;head = node;}}//尾插法O(1)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;}}//任意位置插入,第一个数据节点为0号下标public void addIndex(int index, int data) {if (index < 0 || index > size()) {throw new ListIndexOutOfException();}if (index == 0) {addFirst(data);return;}if (index == size()) {addLast(data);return;}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;while (index != 0) {cur = cur.next;index--;}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;}//删除第一次出现关键字为key的节点public void remove(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {//1. 删除的是头节点if (cur == head) {head = head.next;//只有一个节点if (head != null) {head.prev = null;}} else {//中间 尾巴cur.prev.next = cur.next;//不是尾巴节点if (cur.next != null) {cur.next.prev = cur.prev;} else {//是尾巴节点last = last.prev;}}return;}cur = cur.next;}}//删除所有值为key的节点public void removeAllKey(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {//1. 删除的是头节点if (cur == head) {head = head.next;//只有一个节点if (head != null) {head.prev = null;}} else {//中间 尾巴cur.prev.next = cur.next;//不是尾巴节点if (cur.next != null) {cur.next.prev = cur.prev;} else {//是尾巴节点last = last.prev;}}}cur = cur.next;}}public int size() {int len = 0;ListNode cur = head;while (cur != null) {len++;cur = cur.next;}return len;}public void display() {ListNode cur = head;while (cur != null) {System.out.println(cur.val + " ");cur = cur.next;}System.out.println();}public void clear() {ListNode cur = head;while (cur != head) {ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = curNext;}head = null;last = null;}
测试代码:
public static void main(String[] args) {MyLinkedList linkedList = new MyLinkedList();linkedList.addLast(1);linkedList.display();}
1. LinkedList实现了List接口
2. LinkedList的底层使用了双向链表
3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
5. LinkedList比较适合任意位置插入的场景
2.2LinkedList其他常用方法介绍
| 方法 | 解释 |
| boolean add(E e) | 尾插 e |
| void add(int index, E element) | 将 e 插入到 index 位置 |
| boolean addAll(Collection<? extends E> c) | 尾插 c 中的元素 |
| E remove(int index) | 删除 index 位置元素 |
| boolean remove(Object o) | 删除遇到的第一个 o |
| E get(int index) | 获取下标 index 位置元素 |
| E set(int index, E element) | 将下标 index 位置元素设置为 element |
| void clear() | 清空 |
| boolean contains(Object o) | 判断 o 是否在线性表中 |
| int indexOf(Object o) | 返回第一个 o 所在下标 |
| int lastIndexOf(Object o) | 返回最后一个 o 的下标 |
| List<E> subList(int fromIndex, int toIndex) | 截取部分 list |
LinkedList<Integer> list = new LinkedList<>();
list.add(1); // add(elem): 表示尾插
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
System.out.println(list.size());
System.out.println(list);
// 在起始位置插入0
list.add(0, 0); // add(index, elem): 在index位置插入元素elem
System.out.println(list);
list.remove(); // remove(): 删除第一个元素,内部调用的是removeFirst()
list.removeFirst(); // removeFirst(): 删除第一个元素
list.removeLast(); // removeLast(): 删除最后元素
list.remove(1); // remove(index): 删除index位置的元素
System.out.println(list);

2.3ArrayList和LinkedList的区别
| 不同点 | ArrayList | LinkedList |
| 存储空间上 | 物理上一定连续 | 逻辑上连续,但物理上不一定连续 |
| 随机访问 | 支持O(1) | 不支持:O(N) |
| 头插 | 需要搬移元素,效率低O(N) | 只需修改引用的指向,时间复杂度为O(1) |
| 插入 | 空间不够时需要扩容 | 没有容量的概念 |
| 应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除频繁 |
相关文章:
Java数据结构LinkedList单链表和双链表模拟实现及相关OJ题秒AC总结知识点
本篇文章主要讲述LinkedList链表中从初识到深入相关总结,常见OJ题秒AC,望各位大佬喜欢 一、单链表 1.1链表的概念及结构 1.2无头单向非循环链表模拟实现 1.3测试模拟代码 1.4链表相关面试OJ题 1.4.1 删除链表中等于给定值 val 的所有节点 1.4.2 反转…...
立创EDA 学习 day01 应用下载安装,基本使用的操作
1.下载网站 1.链接:立创EDA下载-立创EDA官方版-PC下载网 (pcsoft.com.cn) 2.安装立创EDA 1.直接 next (简单的操作) 3.注册账号 1. 最好注册一个账号,等下在原理图转PCB 板的时候要登录,才可以。 4.新建工程 1.新…...
华为OD机试真题Python实现【火星文计算】真题+解题思路+代码(20222023)
火星文计算 题目 已经火星人使用的运算符号为# $ 其与地球人的等价公式如下 x#y=2*x+3*y+4 x$y=3*x+y+2 x y是无符号整数 地球人公式按照 c 语言规则进行计算 火星人公式中$符优先级高于#相同的运算符按从左到右的顺序运算 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华…...
yolov8 修改类别 自定义数据集
yolov8 加载yolo网络模型 yolov8n.yaml nc: 80 # number of classes 分类数量 depth_multiple: 0.33 # scales module repeats 重复规模 width_multiple: 0.25 # scales convolution channels 缩放卷积通道 backbone head 指定配置 coco128.yaml path: ../datasets/coco128 # d…...
Linux环境下验证python项目
公司大佬开发的python rpa跑数项目,Windows运行没问题后,需要搭建一个linux环境进行验证,NOW START! Install VMware官网 下载好之后打开按步骤安装 最后一步会让填许可证(密钥),这里自行百…...
MAC开发使用技巧
1. 查看所有安装的程序 您可以通过以下步骤在 macOS 中查看所有已安装的程序: 点击屏幕左上角的苹果图标,选择“关于本机”。 在打开的窗口中,选择“系统报告”。 在系统报告窗口中,选择“软件”选项卡,然后选择“安…...
第三章-OpenCV基础-7-形态学
前置 形态学主要是从图像中提取分量信息,该分量信息通常是图像理解时所使用的最本质的形状特征,对于表达和描绘图像的形状有重要意义。 大体就是通过一系列操作让图像信息中的关键信息更加凸出。同时,形态学的操作都是基于灰度图进行。 相关操作最主要…...
DeepFaceLab 中Ubuntu(docker gpu) 部署
DeepFaceLab 在windows图形界面部署比较多,下面用ubuntu 部署在服务器上。部署过程中python版本,或者protobuf版本可能有问题,所以建议用docker 代码下载 cd /trainssdgit clone --depth 1 https://github.com/nagadit/DeepFaceLab_Linux.g…...
分析帆软填报报表点提交的逻辑
1 点提交这里首先会校验数据,校验成功后就去入库数据,这里不分析校验,分析下校验成功后数据是怎么入库的。 2 我们知道当点提交时,发送的请求中的参数为 op=fr_write,cmd=submit_w_report. 在帆软报表中op表示服务,cmd表示服务中的一个动作处理。比如op=fr_write这个服务…...
【ROS学习笔记9】ROS常用API
【ROS学习笔记9】ROS常用API 文章目录【ROS学习笔记9】ROS常用API前言一、 初始化二、 话题与服务相关对象三、 回旋函数四、时间函数五、其他函数Reference写在前面,本系列笔记参考的是AutoLabor的教程,具体项目地址在 这里 前言 ROS的常用API…...
客户关系管理挑战:如何保持客户满意度并提高业绩?
当今,各行业市场竞争愈发激烈,对于保持客户满意度并提高业绩是每个企业都面临的挑战。而客户关系管理则是实现这一目标的关键,因为它涉及到与客户的互动和沟通,以及企业提供优质的产品和服务。在本文中,我们将探讨客户…...
Cartesi 2023 年 2 月回顾
2023年2月28日,通过ETH Denver和Cartesi的在线全球黑客马拉松一起开启黑客马拉松赛季!ETH Denver 正在热火朝天的进行着,我们正在为3月25日开始的首个全球在线黑客马拉松做准备。但这并不是本月发生的所有事情。我们在继续扩展和发展在全世界各地的社区&…...
《爆肝整理》保姆级系列教程python接口自动化测试框架(二十六)--批量执行用例 discover(详解)
简介 我们在写用例的时候,单个脚本的用例好执行,那么多个脚本的时候,如何批量执行呢?这时候就需要用到 unittest 里面的 discover 方法来加载用例了。加载用例后,用 unittest 里面的 TextTestRunner 这里类的 run 方…...
Ubuntu学习篇
前言 环境:Ubuntu 20.4lts Ubuntu系统跟centos还是有很多区别的,笔者之前一直使用的是centos7.x版本。 镜像下载地址:https://ubuntu.com/download/server#downloads 其他版本下载地址:https://launchpad.net/ubuntu/cdmirrors&a…...
extern关键字
1、基本解释: extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和数时在其他模块中寻找其定义。此外extern也可用来进行链接指定。 也就是说extern有两个作用。 第一个,当它与"C"一起…...
T3 出行云原生容器化平台实践
作者:林勇,就职于南京领行科技股份有限公司,担任云原生负责人,也是公司容器化项目的负责人。主要负责 T3 出行云原生生态相关的所有工作,如服务容器化、多 Kubernetes 集群建设、应用混部、降本增效、云原生可观测性基…...
从0开始学python -44
Python3 正则表达式 -2 检索和替换 Python 的re模块提供了re.sub用于替换字符串中的匹配项。 语法: re.sub(pattern, repl,string, count0, flags0)参数: pattern : 正则中的模式字符串。repl : 替换的字符串,也可为一个函数。string : …...
22- estimater使用 (TensorFlow系列) (深度学习)
知识要点 estimater 有点没理解透 数据集是泰坦尼克号人员幸存数据. 读取数据:train_df pd.read_csv(./data/titanic/train.csv) 显示数据特征:train_df.info() 显示开头部分数据:train_df.head() 提取目标特征:y_train tr…...
eKuiper 1.8.0 发布:零代码实现图像/视频流的实时 AI 推理
LF Edge eKuiper 是 Golang 实现的轻量级物联网边缘分析、流式处理开源软件,可以运行在各类资源受限的边缘设备上。eKuiper 的主要目标是在边缘端提供一个流媒体软件框架(类似于 Apache Flink )。eKuiper 的规则引擎允许用户提供基于 SQL 或基…...
[Ansible系列]ansible JinJia2过滤器
目录 一. JinJia2简介 二. JinJia2模板使用 2.1 在play中使用jinjia2 2.2 template模块使用 2.3 jinjia2条件语句 2.4 jinjia2循环语句 2.5 jinjia2过滤器 2.5.1 default过滤器 2.5.2 字符串操作相关过滤器 2.5.3 数字操作相关过滤器 2.5.4 列表操作…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...

