【Java数据结构】详解LinkedList与链表(三)

🔒文章目录:

1.❤️❤️前言~🥳🎉🎉🎉

2.无头双向非循环链表的实现

2.1成员属性

2.2成员方法 

display——打印链表 

 size——获取单链表长度 

addFirst——头插 

 addLast——尾插 

addIndex——在任意位置插入 

 contains——判定是否包含某个元素 

remove——删除第一次出现关键字为key的结点 

 removeAll——删除所有值为key的结点  

clear——清空单链表  

2.3完整代码及使用

完整代码

完整代码的使用

3.总结


1.❤️❤️前言~🥳🎉🎉🎉

Hello, Hello~ 亲爱的朋友们👋👋,这里是E绵绵呀✍️✍️。

如果你喜欢这篇文章,请别吝啬你的点赞❤️❤️和收藏📖📖。如果你对我的内容感兴趣,记得关注我👀👀以便不错过每一篇精彩。

当然,如果在阅读中发现任何问题或疑问,我非常欢迎你在评论区留言指正🗨️🗨️。让我们共同努力,一起进步!

加油,一起CHIN UP!💪💪

🔗个人主页:E绵绵的博客
📚所属专栏:

1. JAVA知识点专栏

        深入探索JAVA的核心概念与技术细节

2.JAVA题目练习

        实战演练,巩固JAVA编程技能

3.c语言知识点专栏

        揭示c语言的底层逻辑与高级特性

4.c语言题目练习

        挑战自我,提升c语言编程能力

📘 持续更新中,敬请期待❤️❤️


2.无头双向非循环链表的实现

2.1成员属性

其成员属性跟无头单向非循环链表的成员属性类似。只是在内部类中多了个prev前驱,以及成员变量多了个last。

public class MyLinkedList {static class ListNode{int val;ListNode next;ListNode  prev;public ListNode(int val) {this.val = val;}}ListNode head;ListNode  last;

2.2成员方法 

display——打印链表 

 注意:MyLinkedList 中不存在该方法,为了方便看测试结果 。

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

 size——获取单链表长度 

   直接遍历链表即可

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

addFirst——头插 

实现思路:

  1. 判断链表是否为空,如果为空,直接将head和last指向新节点listNode。
  2. 如果链表不为空,将新节点listNode的next指向当前头节点head,当前头节点head的prev指向新节点listNode,最后将head指向新节点listNode,完成头插操作。
   public  void addFirst(int a){ListNode listNode = new ListNode(a);if(head==null){head=listNode;last=listNode;}else{listNode.next=head;head.prev=listNode;head=listNode;}}

 addLast——尾插 

实现思路与头插法类似:

  1. 判断链表是否为空,如果为空,则将头结点 head 和尾结点 last 都指向新节点 listNode。

  2. 如果链表不为空,将新节点 listNode 的 prev 指针指向当前的尾结点 last,将当前的尾结点 last 的 next 指针指向新节点 listNode,然后将尾结点 last 更新为新节点 listNode。

     public  void addLast(int a){ListNode listNode = new ListNode(a);if(last==null){head=listNode;last=listNode;}else{listNode.prev=last;last.next=listNode;last=listNode;}}

addIndex——在任意位置插入 

具体实现步骤如下:

  1. 判断链表是否为空。如果为空,则新建一个节点listNode,并将头结点head指向listNode,然后返回。

  2. 判断index是否越界。如果小于0或者大于链表长度size(),则抛出自定义异常MyIndexException,打印异常堆栈信息,然后返回。

  3. 如果index等于0,则调用addFirst(a)方法在链表头部添加元素a,然后返回。

  4. 如果index等于size(),则调用addLast(a)方法在链表尾部添加元素a,然后返回。

  5. 否则,新建一个节点listNode,并遍历链表找到第index-1个节点cur。

  6. 将cur节点的后继节点的前驱指针指向listNode节点。

  7. 将listNode节点的前驱指针指向cur节点。

  8. 将listNode节点的后继指针指向cur节点的后继节点。

  9. 将cur节点的后继指针指向listNode节点。

​
public void addIndex(int index,int a){if(head==null){ListNode listNode = new ListNode(a);head=listNode;return;}if(index<0||index>size()){try{throw new  MyIndexException("位置不合法");}catch(Exception e){e.printStackTrace();}return;}if(index==0){addFirst(a);return;}if(index==size()){addLast(a);return;}ListNode listNode = new ListNode(a);ListNode cur=head;for (int i = 0; i <index-1 ; i++) {cur=cur.next;}cur.next.prev=listNode;listNode.prev=cur;listNode.next=cur.next;cur.next=listNode;}​class MyIndexException extends RuntimeException{public MyIndexException(String message) {super(message);}
}

 contains——判定是否包含某个元素 

   比较简单,遍历这个数组即可

  public void  contain(int key){ListNode cur=head;while(cur!=null){if(cur.val==key){System.out.println(true);return;}cur=cur.next;}System.out.println(false);}

 因为这里我们存放的是 int 类型的变量,但 LinkedList 当中是存放引用数据类型的
⚠️⚠️⚠️当表中是引用类型时,就不可以用“等号”比较,应该用 equals 方法

remove——删除第一次出现关键字为key的结点 

首先判断链表是否为空,若为空则输出“为空链表,不能进行删除操作”,并直接返回。

若链表不为空,则判断头节点head的值是否等于给定key值。如果是,将head指向下一个节点,并将原来的head节点删除。如果此时head已经变成空节点,说明该链表只有一个节点,直接更新last为null;否则,将head节点的前驱指针设为null。

如果头节点的值不等于给定key值,则从头节点的后继开始遍历链表。当遇到某个节点的值等于给定key值时,将该节点的前驱节点指向该节点的后继节点,并将该节点删除。

如果整个链表中不存在值等于给定key值的节点,则输出“不存在该数”

   public void remove(int key){ListNode cur=head;if(head==null) {System.out.println("为空链表,不能进行删除操作");return;}if(cur.val==key) {head=head.next;if(head==null){last=null;}elsehead.prev=null;return;}while(cur.next!=null){if(cur.next.val==key){cur.next.next.prev=cur;cur.next=cur.next.next;return;}cur=cur.next;}System.out.println("不存在该数");}

 removeAll——删除所有值为key的结点  

首先判断链表是否为空,如果为空则无法进行删除操作,直接返回。

然后从头节点开始遍历链表,每次检查当前节点的下一个节点的值是否等于 key,如果相等,则把当前节点的下一个节点删除(即把当前节点的 next 指针指向下下个节点),同时要把下下个节点的 prev 指针指向当前节点。

如果当前节点的下一个节点的值不等于 key,则把当前节点移动到下一个节点。

最后,如果头节点的值等于 key,需要特殊处理头节点,将头节点指向下一个节点。如果此时头节点已经为空,则需要将尾节点也设为 null;否则我们就将新的头节点的 prev 指针设为 null。

public void removeAll(int key){if(this.head == null) {System.out.println("为空链表,不能进行删除操作");return;}ListNode cur = head;while(cur.next != null){if(cur.next.val == key){cur.next.next.prev=cur;cur.next=cur.next.next;}else {cur = cur.next;}}if(head.val==key){head = head.next;if(head==null){last=null;}elsehead.prev=null;}}

clear——清空单链表  

该方法首先要判断头节点是否为空,若为空,则直接返回。若不为空,则通过一个while循环,将每个节点的前驱和后继均置为null,以便垃圾回收机制及时回收节点所占用的内存。最后,将头节点和尾节点均置为null,以实现链表清空。

如果节点中的val是引用类型,则需要将其也全变为null。基本类型则不需要。

   public void clear(){while (head==null)return;ListNode cur=head;while (cur!=null){cur.prev=null;ListNode temp=cur.next;cur.next=null;cur=temp;}head=null;last=null;}

当然也存在暴力解法,就是直接将head=null,last=null,也能得到一样的效果。

  public void clear(){head=null;last=null;}

此时链表中的各个节点中 就不存在 有固定存在的引用去指向它们,它们节点自己的互相指向就形成了个死循环,此时系统就默认将这些节点自动回收掉,所以能得到一样的效果。


对于无头单向非循环链表中的clear我们采用的是暴力解法,当然也可以像这里一样把引用变量全都变为null,都是可取的,效果一样。我个人还是比较喜欢暴力解法。

2.3完整代码及使用

完整代码

​
public class MyLinkedList {static class ListNode{int val;ListNode next;ListNode  prev;public ListNode(int val) {this.val = val;}}ListNode head;ListNode  last;public void display(){ListNode cur=head;if(head==null)return;while(cur!=null){System.out.print(cur.val+"  ");cur=cur.next;}System.out.println();}public int size(){ListNode cur=head;int count=0;while(cur!=null){cur =cur.next;count++;}return  count;}public  void addFirst(int a){ListNode listNode = new ListNode(a);if(head==null){head=listNode;last=listNode;}else{listNode.next=head;head.prev=listNode;head=listNode;}}public  void addLast(int a){ListNode listNode = new ListNode(a);if(last==null){head=listNode;last=listNode;}else{listNode.prev=last;last.next=listNode;last=listNode;}}public void addIndex(int index,int a){if(head==null){ListNode listNode = new ListNode(a);head=listNode;return;}if(index<0||index>size()){try{throw new  MyIndexException("位置不合法");}catch(Exception e){e.printStackTrace();}return;}if(index==0){addFirst(a);return;}if(index==size()){addLast(a);return;}ListNode listNode = new ListNode(a);ListNode cur=head;for (int i = 0; i <index-1 ; i++) {cur=cur.next;}cur.next.prev=listNode;listNode.prev=cur;listNode.next=cur.next;cur.next=listNode;}public void remove(int key){ListNode cur=head;if(head==null) {System.out.println("为空链表,不能进行删除操作");return;}if(cur.val==key) {head=head.next;if(head==null){last=null;}elsehead.prev=null;return;}while(cur.next!=null){if(cur.next.val==key){cur.next.next.prev=cur;cur.next=cur.next.next;return;}cur=cur.next;}System.out.println("不存在该数");}public void removeAll(int key){if(this.head == null) {System.out.println("为空链表,不能进行删除操作");return;}ListNode cur = head;while(cur.next != null){if(cur.next.val == key){cur.next.next.prev=cur;cur.next=cur.next.next;}else {cur = cur.next;}}if(head.val==key){head = head.next;if(head==null){last=null;}elsehead.prev=null;}}public void clear(){while (head==null)return;ListNode cur=head;while (cur!=null){cur.prev=null;ListNode temp=cur.next;cur.next=null;cur=temp;}head=null;last=null;}public void  contain(int key){ListNode cur=head;while(cur!=null){if(cur.val==key){System.out.println(true);return;}cur=cur.next;}System.out.println(false);}}​class MyIndexException extends RuntimeException{public MyIndexException(String message) {super(message);}
}

 完整代码的使用

public class Test {public static void main(String[] args) {MyLinkedList myLinkedList = new MyLinkedList();myLinkedList.addFirst(110);myLinkedList.addFirst(15);myLinkedList.addLast(45);myLinkedList.addLast(64);myLinkedList.addLast(43);myLinkedList.addIndex( 4,45);myLinkedList.addFirst(45);myLinkedList.display();myLinkedList.remove(15);myLinkedList.removeAll(45);myLinkedList.display();myLinkedList.contain(110);System.out.println(myLinkedList.size());}
}

3.总结

这篇文章我们就将无头双向非循环链表的模拟讲清楚了,它跟无头单向非循环链表的模拟很相似,但还是有一点区别的。我们下篇文章将给大家带来LinkedList的使用。在此,我们诚挚地邀请各位大佬们为我们点赞、关注,并在评论区留下您宝贵的意见与建议。让我们共同学习,共同进步,为知识的海洋增添更多宝贵的财富!🎉🎉🎉❤️❤️💕💕🥳👏👏👏

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

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

相关文章

Application UI

本节包含关于如何用DevExpress控件模拟许多流行的应用程序ui的教程。 Windows 11 UI Windows 11和最新一代微软Office产品启发的UI。 Office Inspired UI Word、Excel、PowerPoint和Visio等微软Office应用程序启发的UI。 How to: Build an Office-inspired UI manually 本教…

数据分析中的统计学基础及Python具体实现【数据分析】

各位大佬好 &#xff0c;这里是阿川的博客&#xff0c;祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 Python 初阶 Python–语言基础与由来介绍 Python–…

layui左侧菜单栏,鼠标悬停显示菜单文字

layui封装的左侧菜单是固定宽度的&#xff0c;且左侧菜单栏在css里改变宽度&#xff0c;效果并不是很好&#xff08;还设计头部菜单栏&#xff09;&#xff0c;如果写js来让菜单栏能够拉伸&#xff0c;也比较麻烦&#xff0c;那怎么最简单的&#xff0c;让用户看到菜单的文字呢…

从混乱到有序:PDM系统如何优化物料编码

在现代制造业中&#xff0c;物料管理是企业运营的核心。物料编码作为物料管理的基础&#xff0c;对于确保物料的准确性、唯一性和高效性至关重要。随着产品种类的不断增加和产品变型的多样化&#xff0c;传统的物料编码管理方式已经不能满足企业的需求。本文将探讨产品数据管理…

SpringSecurity6从入门到实战之默认用户的生成流程

SpringSecurity6从入门到实战之默认用户的生成流程 这次还是如标题所示,上一章我们的登录页面已经知道是如何生成了.那么,我们通过表单登录的user用户以及密码SpringSecurity是如何进行生成的呢? 默认用户生成 让我们把登录流程重新拉回到读取/META-INF/spring/ .imports文件 …

什么是MES系统?有什么作用?

MES系统解决方案是专门针对制造企业设计&#xff0c;在MES系统的应用下&#xff0c;实现专业的工厂、车间生产信息化管理方案&#xff0c;帮助制造企业提高生产效率。针对目前制造行业的生产管理状况&#xff0c;以及提升企业生产效率和企业竞争力的需求&#xff0c;实施MES系统…

《尚庭公寓》项目部署之Docker + Nginx

docker rmi nginx docker pull nginx docker rm -f nginx #先创建一个简易的nginx容器&#xff08;后面会删&#xff09;&#xff0c;然后通过 docker cp命令把容器里面的nginx配置反向拷贝到宿主主机上。 docker run --name nginx -p 80:80 -d nginx# 将容器nginx.conf文件复…

小猪APP分发:高效的APP托管服务分发平台

有没有遇到过这样的尴尬&#xff1f;辛辛苦苦开发了一个APP&#xff0c;却在托管和分发环节卡壳。想想看&#xff0c;花了那么多时间精力开发的APP&#xff0c;却因为分发不顺利而影响用户体验&#xff0c;实在是让人抓狂。而小猪APP分发就成了你最好的选择。 APP封装分发www.…

pypi 发布自己的包

注册pypi个人用户 网址&#xff1a;https://pypi.org 目录结构dingtalk_utils 必须-pkgs- __init__.py .gitignore LICENSE 必须 README.md 必须 requirements.txt setup.py 必须安装依赖 pip install setuptools wheel安装上传工具 pip install twinesetup.py i…

PHP质量工具系列之php-depend

php-depend是一个开源的静态代码分析工具&#xff0c;它的主要功能包括&#xff1a; 代码质量分析 复杂度度量&#xff1a;计算类、方法和函数的Cyclomatic Complexity&#xff08;循环复杂度&#xff09;&#xff0c;帮助识别潜在的复杂代码段。 耦合度度量&#xff1a;分析类…

推荐网站(20)ai工具集,你想要的ai工具里面都有

今天&#xff0c;我要向您介绍一个综合性的在线平台——AI工具集&#xff0c;这是一个集成了多种人工智能工具的网站&#xff0c;旨在为用户提供一站式的智能解决方案。无论您是专业人士、创意工作者&#xff0c;还是仅仅对AI技术感兴趣的普通用户&#xff0c;AI工具集都能满足…

Pico4 MR Unity零基础开发之获取手柄按键

一、导入示例资源 1、打开Package Manager面板&#xff0c;导入示例资源。 2、打开示例场景&#xff0c;方面后面测试。 二、打开 XRI Default Input Actions 三、设置XRI Default Input Actions 面板参数 1、点击号新增一项&#xff0c;重命名为Pico 2、新增并重命名Action …

springboot启动配置文件-bootstrap.yml常用基本配置

4.1.5.配置文件 SpringBoot的配置文件支持多环境配置&#xff0c;基于不同环境有不同配置文件&#xff1a; 说明&#xff1a; 文件说明bootstrap.yml通用配置属性&#xff0c;包含服务名、端口、日志等等各环境通用信息bootstrap-dev.yml线上开发环境配置属性&#xff0c;虚…

PICRUSt2在微生物功能预测分析中的应用解读

谷禾健康 微生物组学研究现已超越微生物群落组成分析得到更广泛的使用。大量的人类微生物组研究证据表明&#xff0c;肠道微生物组的功能变化对炎症和免疫反应的影响起到关键的影响作用。 16S rRNA分析是微生物组研究作为最常用便捷且具有成本效益的测量技术&#xff0c;用于分…

springboot+minio+kkfileview实现文件的在线预览

在原来的文章中已经讲述过springbootminio的开发过程&#xff0c;这里不做讲述。 原文章地址&#xff1a; https://blog.csdn.net/qq_39990869/article/details/131598884?spm1001.2014.3001.5501 如果你的项目只是需要在线预览图片或者视频那么可以使用minio自己的预览地址进…

Java面试——中间件

OpenFeign 1、openFeign是一个HTTP客户端&#xff0c;它融合了springmvc的注解&#xff0c;使之可以用REST风格的映射来请求转发。 2、可以把openFegin理解为是controller层或是service层。可以取代springmvc控制层作为请求映射&#xff0c;亦或是作为service层处理逻辑&#…

Three.js和Babylon.js,webGL中的对比效果分析!

hello&#xff0c;今天分享一些three.js和babylon.js常识&#xff0c;为大家选择three.js还是babylon.js做个分析&#xff0c;欢迎点赞评论转发。 一、Babylon.js是什么 Babylon.js是一个基于WebGL技术的开源3D游戏引擎和渲染引擎。它提供了一套简单易用的API&#xff0c;使开发…

Threejs-02、坐标辅助器与轨道控制器使用

一、坐标辅助器 1、添加坐标辅助器 // 添加世界坐标辅助器 const axesHelper = new THREE.AxesHelper(2); scene.add(axesHelper);2、调整相机位置 //设置相机位置 camera.

卫星通信频段有哪些

卫星通信使用到的频段涵盖L, S, C, Ku, Ka等&#xff0c;而最常用的频段是C(4~8GHz)和Ku(12~18GHz)频段&#xff0c;而Ka(27-40GHz)频段是后起之秀。目前地球赤道上空有限的地球同步卫星轨位几乎已被各国占满&#xff0c;C和Ku频段内的频率资源被大量使用&#xff0c;而Ka频段的…

微软必应地图的三维实景功能

偶然看到微软必应地图的三维实景功能&#xff0c;由于比较感兴趣这方面的技术&#xff0c;所以试用了一下,感觉总体来说技术上比咱们自己的技术和设计要好很多。比如这个工具栏就设计的很简洁&#xff0c;人性化&#xff1a; 而且实景地图的范围也非常大&#xff0c;建立这么大…