Java数据结构-双向不带头非循环链表(模拟实现LinkedList)

目录

  • 1. 双向不带头非循环链表的介绍
  • 2. 相关功能的实现
    • 2.1 基本框架
    • 2.2 size
    • 2.3 addFirst
    • 2.4 addLast
    • 2.5 addIndex
    • 2.6 contains
    • 2.7 remove
    • 2.8 removeAllKey
    • 2.9 clear
  • 3. 全部代码

前面我们学习了最简单的链表:单链表,今天我们学习双向不带头非循环链表,这也是Java的集合框架中LinkedList的底层实现

1. 双向不带头非循环链表的介绍

双向指的是:每个链表结点有三个域,一个是数据域,另外两个保存了前驱结点的地址和后继结点的地址,如图,第一个结点的前驱为null,最后一个结点的后继也为null
在这里插入图片描述

2. 相关功能的实现

2.1 基本框架

同样定义泛型类myLinkedList,每个结点定义为静态内部类ListNode,提供构造方法给val初始化,定义结点first表示链表的第一个结点,定义last表示链表的最后一个结点

public class myLinkedList<T> {//结点类static class ListNode {public ListNode prev;//前驱public Object val;//数据public ListNode next;//后继//构造方法public ListNode(Object val) {this.val = val;}}public ListNode first;//第一个结点public ListNode last;//最后一个结点//....其他方法
}

2.2 size

size的功能是获取链表长度,定义计数器size,遍历链表每个结点,每遍历一个结点size+1,直至遍历完链表,返回size

    //得到单链表的长度public int size() {int size = 0;ListNode cur = first;while (cur != null) {cur = cur.next;size++;}return size;}

2.3 addFirst

addFirst意为头插,在链表的头部插入数据,如果链表没有数据,first等于null,则让first和last等于新的结点,然后return;如果链表已有数据,先让新的结点绑定链表,再让原来的头部的prev指向新的结点,接着更新first

    //头插法public void addFirst(T val) {ListNode newNode = new ListNode(val);//如果没有元素if (first == null) {first = last = newNode;return;}newNode.next = first;first.prev = newNode;first = newNode;}

在这里插入图片描述

2.4 addLast

addLast表示尾插,在链表尾部插入数据,如果链表没有数据,让first和last等于新的结点,然后return;如果链表已有数据,让新的结点的prev指向链表的last,接着让last的next指向新的结点,然后更新last的值

    //尾插法public void addLast(T val) {ListNode newNode = new ListNode(val);//如果没有元素if (last == null) {first = last = newNode;return;}newNode.prev = last;last.next = newNode;last = newNode;}

在这里插入图片描述

2.5 addIndex

addIndex表示在Index位置插入数据,插入前需要判断Index的合法性(Index不能小于0,不能大于链表的长度),定义IndexNotLegalException异常类,如果Index不合法就抛出这个异常

public class IndexNotLegalException extends RuntimeException {public IndexNotLegalException(String s) {super(s);}public IndexNotLegalException() {super();}
}

如果Index等于0,表示头插,如果Index等于链表长度,表示尾插,此时直接调用方法;在插入之前先找到Index位置的结点,接着先绑定后面的数据

    //任意位置插入,第一个数据节点为0号下标public void addIndex(int index, T val) {ListNode newNode = new ListNode(val);//index合法性检查try {if (index < 0 || index > size()) {throw new IndexNotLegalException("Index不合法");}} catch (IndexNotLegalException e) {e.printStackTrace();}//index=0 头插if (index == 0) {addFirst(val);return;}//index=size 尾插if (index == size()) {addLast(val);return;}//ListNode cur = first;for (int i = 0; i < index; i++) {cur = cur.next;}ListNode prev = cur.prev;//开始绑定newNode.next = cur;newNode.prev = prev;       prev.next = newNode;cur.prev = newNode;}

在这里插入图片描述

2.6 contains

查找链表中是否包含某个数据(key),如果包含返回true否则,返回false

    //查找是否包含关键字key是否在单链表当中public boolean contains(T key) {if (first == null) {return false;}ListNode cur = first;while (cur != null) {if (cur.val.equals(key)) {return true;}cur = cur.next;}return false;}

2.7 remove

删除链表中第一个值为key的结点,如果链表为空,直接返回。定义del来遍历链表,如果del的值与key相等,分情况讨论:
1.del为第一个结点,此时只需将first指向下一个结点即可
2.del为最后一个结点,此时将last指向前一个结点,然后将last的next置为空
3.一般情况:要删除的结点在中间,定义两个变量:prevNode,表示要删除的结点的前一个结点;nextNode,表示要删除的结点的后一个结点,让prevNode的next指向nextNode,让nextNode的prev指向prevNode,此时就跳过了要删除的结点,没人引用它也就意味着删除了它

    //删除第一次出现关键字为key的结点public void remove(T key) {if (first == null) {return;}ListNode del = first;while (del != null) {if (del.val.equals(key)) {//删除ListNode preNode = del.prev;ListNode nextNode = del.next;//pre==null?if (pre == null) {//第一个是keyfirst = first.next;return;}if (next == null) {//最后一个是keylast = last.prev;last.next = null;return;}preNode.next = nextNode;nextNode.prev = preNode;return;}del = del.next;}}

2.8 removeAllKey

删除链表中所有值为key的结点,分情况讨论:
1.前面部分全是要删除的结点:first往后走,如果first为空了,说明整个链表的值都是key,这个时候直接return
2.后面部分全是要删除的结点:让last往前走
3.一般情况:情况1处理了链表前部分都是key的情况,情况2处理了链表后部分都是key的情况,此时的key只能出现在中间部分,删除的逻辑remove一样,只不过remove删除完一个之后return了,removeAllKey则是删除之后继续删除

    //删除所有值为key的结点public void removeAllKey(T key) {if (first == null) {return;}//处理前面的keywhile (first.val.equals(key)) {first = first.next;if (first == null) {return;}}//处理后面的keywhile (last.val.equals(key)) {last = last.prev;last.next = null;}//ListNode del = first;while (del != null) {if (del.val.equals(key)) {//删除ListNode preNode = del.prev;ListNode nextNode = del.next;//preNode.next = next;nextNode.prev = preNode;}del = del.next;}}

2.9 clear

clear表示将链表置空,只需循环遍历链表,将每一个结点都置空

    public void clear() {while (first != null) {ListNode next = first.next;first.prev = first.next = null;first = next;}last = null;}

3. 全部代码

//不带头 双向 非循环 链表
public class myLinkedList<T> {//结点类static class ListNode {public ListNode prev;//前驱public Object val;//数据public ListNode next;//后继//构造方法public ListNode(Object val) {this.val = val;}}public ListNode first;//第一个结点public ListNode last;//最后一个结点//头插法public void addFirst(T val) {ListNode newNode = new ListNode(val);//如果没有元素if (first == null) {first = last = newNode;return;}newNode.next = first;first.prev = newNode;first = newNode;}//尾插法public void addLast(T val) {ListNode newNode = new ListNode(val);//如果没有元素if (last == null) {first = last = newNode;return;}newNode.prev = last;last.next = newNode;last = newNode;}//任意位置插入,第一个数据节点为0号下标public void addIndex(int index, T val) {ListNode newNode = new ListNode(val);//index合法性检查try {if (index < 0 || index > size()) {throw new IndexNotLegalException("Index不合法");}} catch (IndexNotLegalException e) {e.printStackTrace();}//index=0 头插if (index == 0) {addFirst(val);return;}//index=size 尾插if (index == size()) {addLast(val);return;}//ListNode cur = first;for (int i = 0; i < index; i++) {cur = cur.next;}ListNode prev = cur.prev;//开始绑定newNode.next = cur;newNode.prev = prev;prev.next = newNode;cur.prev = newNode;}//查找是否包含关键字key是否在单链表当中public boolean contains(T key) {if (first == null) {return false;}ListNode cur = first;while (cur != null) {if (cur.val.equals(key)) {return true;}cur = cur.next;}return false;}//删除第一次出现关键字为key的节点public void remove(T key) {if (first == null) {return;}//ListNode del = first;while (del != null) {if (del.val.equals(key)) {//删除ListNode pre = del.prev;ListNode next = del.next;//pre==null?if (pre == null) {//第一个是keyfirst = first.next;return;}if (next == null) {//最后一个是keylast = last.prev;last.next = null;return;}pre.next = next;next.prev = pre;return;}del = del.next;}}//删除所有值为key的节点public void removeAllKey(T key) {if (first == null) {return;}//处理前面的keywhile (first.val.equals(key)) {first = first.next;if (first == null) {return;}}while (last.val.equals(key)) {last = last.prev;last.next = null;}//ListNode del = first;while (del != null) {if (del.val.equals(key)) {//删除ListNode pre = del.prev;ListNode next = del.next;//pre.next = next;next.prev = pre;}del = del.next;}}//得到单链表的长度public int size() {int size = 0;ListNode cur = first;while (cur != null) {cur = cur.next;size++;}return size;}public void clear() {while (first != null) {ListNode next = first.next;first.prev = first.next = null;first = next;}last = null;}
}

今天的内容就到这里,感谢老铁们的点赞、收藏、评论~❤

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

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

相关文章

分布式图床项目

一、图床架构分析 二、后台数据处理框架 秒传: 如果上传的文件已经在服务器中存在了,就不需要二次上传了,但是服务器会对这个文件的引用计数加一,这样服务器就知道这个文件是多个人持有的。先对上传的文件进行 md5 校验来判断服务器中已经存在相同的文件了(同样的文件拿到…

OpenHarmony无人机MAVSDK开源库适配方案分享

MAVSDK 是 PX4 开源团队贡献的基于 MavLink 通信协议的用于无人机应用开发的 SDK&#xff0c;支持多种语言如 C/C、python、Java 等。通常用于无人机间、地面站与通信设备的消息传输。 MAVLink 是一种非常轻量级的消息传递协议&#xff0c;用于与无人机&#xff08;以及机载无…

[flink 实时流基础]源算子和转换算子

文章目录 1. 源算子 Source1. 从集合读2. 从文件读取3. 从 socket 读取4. 从 kafka 读取5. 从数据生成器读取数据 2. 转换算子基本转换算子&#xff08;map/ filter/ flatMap&#xff09; 1. 源算子 Source Flink可以从各种来源获取数据&#xff0c;然后构建DataStream进行转换…

Day55:WEB攻防-XSS跨站CSP策略HttpOnly属性Filter过滤器标签闭合事件触发

目录 XSS跨站-安全防御-CSP XSS跨站-安全防御-HttpOnly XSS跨站-安全防御-XSSFilter(过滤器的意思) 1、无任何过滤 2、实体化 输入框没有 3、全部实体化 利用标签事件 单引号闭合 4、全部实体化 利用标签事件 双引号闭合 5、事件关键字过滤 利用其他标签调用 双引号闭合…

代码随想录训练营第60天 | LeetCode 84.柱状图中最大的矩形、总结

LeetCode 84.柱状图中最大的矩形 文章讲解&#xff1a;代码随想录(programmercarl.com) 视频讲解&#xff1a;单调栈&#xff0c;又一次经典来袭&#xff01; LeetCode&#xff1a;84.柱状图中最大的矩形_哔哩哔哩_bilibili 思路 代码如下&#xff1a; ​​​​​​总结 感…

代码随想录|Day28|贪心03|1005.K次取反后最大化的数组和、134.加油站、135.分发糖果

1005.K次取反后最大化的数组和 思路&#xff1a; 优先取反 绝对值最大的负数如果没有负数&#xff0c;不断取反 绝对值最小的数&#xff0c;直到次数 K 耗尽 取反最小数有一个优化技巧&#xff1a; 如果 K 为偶数&#xff0c;则取反 K 次后&#xff0c;正负不变。如果 K 为奇数…

ROM-IP

1.原理 通过添加数据文件&#xff0c;使ROM看起来不是易失性存储器&#xff0c; 产生256个数据&#xff0c;每个数据的位宽是8 如果前面为x&#xff0c;后面就是x256-1 2.单端口ROM配置 FPGA内部没有非易失性存储器。调用的ROM和RAM都是用RAM来生成的 3.双端口ROM配置 使用第一…

马斯克旗下xAI发布Grok-1.5,相比较开源的Grok-1,各项性能大幅提升,接近GPT-4!

本文原文来自DataLearnerAI官方网站&#xff1a;马斯克旗下xAI发布Grok-1.5&#xff0c;相比较开源的Grok-1&#xff0c;各项性能大幅提升&#xff0c;接近GPT-4&#xff01; | 数据学习者官方网站(Datalearner) 继Grok-1开源之后&#xff0c;xAI宣布了Grok-1.5的内测消息&…

手撕算法-跳跃游戏

描述 分析 如果某一个作为 起跳点 的格子可以跳跃的距离是 3&#xff0c;那么表示后面 3 个格子都可以作为 起跳点可以对每一个能作为 起跳点 的格子都尝试跳一次&#xff0c;把 能跳到最远的距离 不断更新如果可以一直跳到最后&#xff0c;就成功了 代码 class Solution {…

07-JavaScript DOM事件

1. 事件 1.1 事件概述 JavaScript 使我们有能力创建动态页面&#xff0c;而事件是可以被 JavaScript 侦测到的行为。 简单理解&#xff1a; 触发--- 响应机制。 网页中的每个元素都可以产生某些可以触发 JavaScript 的事件&#xff0c;例如&#xff0c;我们可以在用户点击某…

【漏洞潜在风险】弹框干扰类风险

弹框干扰风险定义: 游戏过程中&#xff0c;客户端经常会以文字类形式对玩家进行说明和指引&#xff0c;而对于一些更为重要的信息&#xff0c;便会用游戏中的弹框进行强调。由玩家主动触发对其他玩家造成重复弹框进而干扰到正常游戏的都可以称之为弹框干扰类风险。弹框干扰风险…

C++项目——集群聊天服务器项目(六)MySQL模块

Hello&#xff0c;大家好啊&#xff0c;最近比较忙&#xff0c;没来得及更新项目&#xff0c;实在抱歉~今天就恢复更新拉~ 在验证完网络模块与业务模块代码可以正常使用后&#xff0c;需完成的操作是与底层数据库进行交互&#xff0c;为实现各类用户查询、增删业务奠定良好的基…

【群晖】白群晖如何公网访问

【群晖】白群晖如何公网访问 ——> 点击查看原文 在使用默认配置搭建好的群晖NAS后&#xff0c;我们可以通过内网访问所有的服务。但是&#xff0c;当我们出差或者不在家的时候也想要使用应该怎么办呢&#xff1f; 目前白群提供了两种比较快捷的方式&#xff0c;一种是直接注…

【Python系列】合并配置文件的最佳实践

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

python实现两个Excel表格数据对比、补充、交叉验证

业务背景 业务中需要用到类似企查查一类的数据平台进行数据导出&#xff0c;但企查查数据不一定精准&#xff0c;所以想采用另一个官方数据平台进行数据对比核验&#xff0c;企查查数据缺少的则补充&#xff0c;数据一致的保留企查查数据&#xff0c;不一致的进行颜色标注。 …

脱壳之常用的加固样本特征

梆梆加固样本特征 清单文件入口 android:name“com.SecShell.SecShell.ApplicationWrapper” 特征 免费版 meta-data meta-data总结 assets/secData0.jar lib/armeabi/libSecShell.so lib/armeabi/libSecShell-x86.so 梆梆企业版 assets/classes0.jar lib/armeabi-v7a/libD…

第一次运行 Python 项目,使用 python-pptx 提取 ppt 中的文字和图片

人工智能时代&#xff0c;最需要学习的编程语言是&#xff1a;python 。笔者是个 python 小白&#xff0c;昨天花了两个小时&#xff0c;第一次成功运行起来 python 项目 。 项目是 powerpoint-extractor &#xff0c;可以将 ppt 文件中的图片提取出来&#xff0c;并输出到固定…

Windows安装tomcat,以服务的方式管理,如何设置虚拟内存

之前工作中&#xff0c;部署tomcat都是使用Linux服务器&#xff0c;最近遇到个客户&#xff0c;提供的服务器是Windows server&#xff0c;并且需要通过服务的方式管理tomcat&#xff1b;以自己多年的码农经验&#xff0c;感觉应该没有问题&#xff0c;结果啪啪打脸了&#xf…

双向BFS

P1032 [NOIP2002 提高组] 字串变换 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 方法学自于B19 双向BFS 字串变换_哔哩哔哩_bilibili #include<iostream> #include<algorithm> #include<cstdio> #include<queue> #include<map> using namesp…

Adaboost集成学习 | Matlab实现基于BiLSTM-Adaboost双向长短期记忆神经网络结合Adaboost集成学习时间序列预测(股票价格预测)

目录 效果一览基本介绍模型设计程序设计参考资料效果一览 基本介绍 Matlab实现基于BiLSTM-Adaboost双向长短期记忆神经网络结合Adaboost集成学习时间序列预测(股票价格预测) 模型设计 股票价格预测是一个具有挑战性的时间序列预测问题,可以使用深度学习模型如双向长短期记忆…