Java数据结构LinkedList单链表和双链表模拟实现及相关OJ题秒AC总结知识点

news/2024/4/30 9:33:06/文章来源:https://blog.csdn.net/asad21654864/article/details/129264791

本篇文章主要讲述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的区别

不同点ArrayListLinkedList
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持:O(N)
头插需要搬移元素,效率低O(N)只需修改引用的指向,时间复杂度为O(1)
插入空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入和删除频繁

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

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

相关文章

vue实现table表格树结构-使用懒加载时-解决子节点增删改后,不刷新子节点数据问题

问题发现 在使用element-ui的table组件时&#xff0c;使用树形结构&#xff0c;并使用了懒加载&#xff0c;可出现了一个问题&#xff0c;在对当前节点添加一个子节点数据&#xff0c;或删除一个子节点数据时&#xff0c;当前节点的子节点数据并不自动刷新出来。element-ui官方…

korean doll likeness模型|Japanese-doll-likeness模型获取及使用

1.模型 之前给大家写了Mac安装stable-diffusion-webui绘制AI妹子保姆级教程&#xff0c;教程在下面 【奶奶看了也不会】AI绘画 Mac安装stable-diffusion-webui绘制AI妹子保姆级教程 今天一早起来打开C站&#xff0c;发现之前热门的几个doll模型都没有了&#xff0c;猜测是某…

2023年湖北助理工程师(初级职称)怎么评?需要什么资料?启程别

2023年湖北助理工程师&#xff08;初级职称&#xff09;怎么评&#xff1f;需要什么资料&#xff1f;启程别 助理工程师主要是指初级工程技术人员的职务名称&#xff0c;他是通过相关考试和相关部门评审通过之后所获得的相应名称&#xff0c;想要了解职称更多相关资料可以咨询启…

pyechart绘制多图(三图及以上)的overlap叠加

pyechart github页面&#xff1a;https://github.com/pyecharts/pyecharts 首先要明确多图叠加到一个图的规则&#xff0c;即多个图只能有一个公共的轴&#xff1a; 比如&#xff0c;横坐标含义相同&#xff08;如时间维度&#xff09;或者&#xff0c;纵坐标取值含义相同 文…

分页与分段

前面我们分析了虚拟地址和物理地址 我们这里进行一个简单的分析 这个是程序运行时的地址映射 那么这些碎片&#xff0c;我们现在的操作系统究竟如何处理呢&#xff1f; 我们再引入一个实际问题 我们如何把右边的进程p塞入左边的内存空间里面 有一种方法将p5kill掉&#xff…

简易计算器-课后程序(JAVA基础案例教程-黑马程序员编著-第十一章-课后作业)

【案例11-2】 简易计算器 【案例介绍】 1.案例描述 本案例要求利用Java Swing 图形组件开发一个可以进行简单的四则运算的图形化计算器。 2.运行结果 运行结果 【案例分析】 要制作一个计算器&#xff0c;首先要知道它由哪些部分组成&#xff0c;如下图所示&#xff1a; 一…

【原创】java+swing+mysql校园订餐管理系统设计与实现

校园订餐管理系统&#xff0c;主要是为了方便广大学生点餐使用&#xff0c;以往的大多数的校园订餐系统基本使用bs架构&#xff0c;也就是网页系统&#xff0c;但是我们今天不用javaweb&#xff0c;我们主要介绍javaswing同样可以去实现一个校园订餐管理系统。 功能分析&#…

「TCG 规范解读」规范结构

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Alli…

软测入门(一)测试理念及基础知识

软测入门理念 软件的分类 按层次划分&#xff1a;系统软件、应用软件按组织划分&#xff1a;商业软件、开源软件按结构划分&#xff1a;单机软件、 软件缺陷 由来 Grace Hopper发明Cobol计算机语言&#xff0c;也是找出电脑程序中第一个bug的女程序员 BugDefect 定义 软…

带你掌握webSocket 和 socket.io的基本用法

两者的作用和区别 作用&#xff1a;使得前后端可以随时地相互沟通。什么是互相沟通呢&#xff1f;像网络请求这种就是客户端向服务端的单向的沟通&#xff0c;当然&#xff0c;网络请求也可以实现双向的沟通&#xff0c;比如ajax 轮询&#xff0c;就是浏览器开个定时器不断的发…

【Java】Java进阶学习笔记(四)—— 抽象类与接口

【Java】Java进阶学习笔记&#xff08;四&#xff09;—— 抽象类与接口一、抽象类1、抽象类的概念抽象类的定义格式2、抽象类的注意点抽象方法的介绍3、抽象类的具体作用4、抽象类实例二、接口&#xff08;一&#xff09;、接口的概念1、接口与类的区别2、接口特性3、抽象类和…

如何实现云原生?推荐的几个实用工具

云原生是一种软件开发和部署的方法&#xff0c;它依赖于容器、微服务和自动化运维。它能使应用更高效、可靠和可扩展&#xff0c;并适用于不同的云平台。 如果要更直接、更通俗地解释上述概念的话。 云的本源更准确地说是一种文化&#xff0c;一种潮流&#xff0c;它必然是云…

此网站可能不支持TLS1.2协议

问题描述 火狐浏览器版本&#xff1a;“97.0.1 (64 位)”&#xff0c;打开360网神设备Web管理地址时出现&#xff1a;“此网站可能不支持TLS1.2协议&#xff0c;而这是Firefox支持的最低版本。”&#xff0c;如下图所示。 原本是默认使用https协议打开的&#xff0c;看起来出问…

蓝桥杯每日一题:不同路径数(dfs深度优先)

给定一个 nm的二维矩阵&#xff0c;其中的每个元素都是一个 [1,9] 之间的正整数。 从矩阵中的任意位置出发&#xff0c;每次可以沿上下左右四个方向前进一步&#xff0c;走过的位置可以重复走。 走了 k 次后&#xff0c;经过的元素会构成一个 (k1) 位数。 请求出一共可以走出…

零基础机器学习做游戏辅助第十五课--原神自动钓鱼(五)完整效果

一、先上效果二、整理思路我们现在已经具备了所有需要的技术&#xff0c;我们梳理出所有技术的流程。判断当前钓鱼状态&#xff08;未抛竿、已抛竿、上鱼中&#xff09;。未抛竿&#xff0c;截图并识别图中所有鱼类&#xff0c;选择其中一个种类。根据以选择鱼类选择对应鱼饵。…

从一个实例配置引入Prometheus的PromQL语法

1. PromQL介绍 PromQL提供对时间序列数据进行逻辑运算、过滤、聚合的支持。应用于数据查询、可视化、告警处理 2. 基本用法 2.1 查询时间序列 点击Prometheus图标,进行查询页面。可以点击地图图标查看有哪些metrics name。输入要查询的metrics name和过滤条件,然后点击执行…

2023年功能测试还值得入行吗?

前言 鉴于笔者从13年入行IT行业&#xff0c;经历了只有开发没有测试的阶段&#xff0c;经历了14年只要会基本的功能测试在一线就能薪资过万的阶段&#xff0c;经历了17年只要会一点自动化&#xff0c;会一点性能就能蒙骗过面试官的阶段&#xff0c;更经历了19年所有面试官对于…

基于大规模边缘计算的千万级聊天室技术实践

当前直播成为一种流行趋势&#xff0c;带货直播&#xff0c;网红带货&#xff0c;明星在线演唱会等&#xff0c;进一步使得直播聊天室变成了一个当前必备的能力&#xff0c;面向大型&#xff0c;超大型的直播场景&#xff0c;技术上也在不断的进行迭代更新。 大规模边缘聊天室如…

如何或者无插件Web页面监控播放软件LiveNVR的固定视频流地址,实现大屏上墙、播放、视频分析等目的

1、LiveNVR介绍 LiveNVR的安防监控的视频直播&#xff0c;可以按标准的Onvif/RTSP协议接入监控设备&#xff0c;也可以通过海康、大华、天地伟业等厂家私有SDK接入监控&#xff0c;实现web页面的播放和录像回放。 可以分发HTTP-FLV、WS-FLV、WebRTC、RTMP、HLS(M3U8)、RTSP等多…

全球化趋势下,如何建设稳定高效的技术能力?

如果将全球化比作一场航行&#xff0c;每个期望走出去的企业都是水手&#xff0c;那么是造一艘属于自己的船&#xff0c;还是搭乘已有的船呢&#xff1f;在不同的时间和场景下&#xff0c;相信每个水手都有自己的答案。 近几年&#xff0c;在国际政经环境复杂变幻的形势之下&am…