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 列表操作…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...