Java链表(2)

🐵本篇文章将对双向链表进行讲解,模拟实现双向链表的常用方法


一、什么是双向链表

双向链表在指针域上相较于单链表,每一个节点多了一个指向前驱节点的引用prev以及多了指向最后一个节点的引用last

二、双向链表的模拟实现

首先将要模拟实现的方法写到IList接口中:

public interface IList {//头插法插入节点public void addFirst(int data);//尾插法插入节点public void addLast(int data);//任意位置插入,第一个数据节点为0号下标public void addIndex(int index,int data);//查找是否包含关键字key是否在链表当中public boolean contains(int key);//删除第一次出现关键字为key的节点public void remove(int key);//删除所有值为key的节点public void removeAllKey(int key);//得到链表的长度public int size();//清除链表public void clear();//显示链表public void display();}

之后再创建一个MyLinkedList类实现上述接口并重写接口中所有的方法

public class MySingleList implements IList{static class ListNode {public int val;public ListNode next;public ListNode prev;public ListNode(int val) {this.val = val;}}public ListNode head; //指向第一个节点public ListNode last; //指向最后一个节点/*以下是要重写IList接口中的方法*/...}

2.1 模拟实现

public void addFirst(int data);

双向链表的头插法和单链表基本一致,只不过当链表为空时不仅要让head指向新节点还要让last也指向新节点

    public void addFirst(int data) {ListNode newNode = new ListNode(data);if (head == null) {head = newNode;last = newNode;return;}newNode.next = head;head.prev = newNode;head = newNode;}

public void addLast(int data);

当链表为空时要让head和last都指向新节点,当链表部不为空时要让最后一个节点的next指向新节点,之后让新节点的prev指向原来的最后一个节点

    public void addLast(int data) {ListNode newNode = new ListNode(data);if (head == null) {head = newNode;last = newNode;return;}last.next = newNode;newNode.prev = last;last = newNode;}

public void addLast(int data);

在任意位置处插入一个节点,第一个节点的索引为0

首先要判断一下index是否合法:

public class IndexException extends RuntimeException{public IndexException(String message) {super(message);}
}=======================================================public void addIndex(int index, int data) {if (index < 0 || index > size()) { //size()为链表长度throw new IndexException("下标错误");}...
}

在任意位置插入节点,所以如果index为0或等于链表长度,就可以直接使用刚刚实现过的头插和尾插方法

public void addIndex(int index, int data) {if (index < 0 || index > size()) {throw new IndexException("下标错误");}if (index == 0) {addFirst(data);}if (index == size()) {addLast(data);}...
}

一般情况下(在中间插入),单链表中要通过循环找到插入位置的前一个节点,但在双向链表中,直接循环到插入位置(插入位置记为cur)即可

    public void addIndex(int index, int data) {if (index < 0 || index > size()) {throw new IndexException("下标错误");}if (index == 0) {addFirst(data);return;}if (index == size()) {addLast(data);return;}ListNode newNode = new ListNode(data);ListNode cur = head;for (int i = 0; i < index; i++) {cur = cur.next;}/*一般情况下*/newNode.next = cur;cur.prev.next = newNode;newNode.prev = cur.prev;cur.prev = newNode;}

public void remove(int key);

删除第一次出现val = key的节点

先考虑常规情况,即通过遍历找到要删除的节点,这里记为cur

让cur的前驱节点的next指向cur的后继节点,cur的后继节点的prev指向cur的前驱节点

    public void remove(int key) {ListNode cur = head;while(cur != null) {if (cur.val == key) {cur.prev.next = cur.next;cur.next.prev = cur.prev;return;}cur = cur.next;}}

之后有两种特殊情况需要考虑:1.cur为第一个节点;2.cur为最后一个节点;当cur为这两种情况时如果使用上述代码,会引发空指针异常,所以这两种情况要单独考虑

1.cur为第一个节点:此时需要让cur的后继节点prev指向空(cur.prev = null),并让head = head.next,但是这样还有一个小问题:当链表中只有一个节点时也会引发空指针异常,这个问题也要单独处理,只需要直接让head = null即可

if (cur == head) {head = head.next;if (head == null) {last = null;} else {head.prev = null;}return;
}

2.cur为最后一个节点:只需让cur的前驱节点的next指向空,并让last = last.prev;即可

if (cur.next == null) {cur.prev.next = null;last = last.prev;return;
}

remove的最终代码如下:

    public void remove(int key) {ListNode cur = head;while(cur != null) {if (cur.val == key) {if (cur == head) {head = head.next;if (head == null) {last = null;} else {head.prev = null;}return;}if (cur.next == null) {cur.prev.next = null;last = last.prev;return;}cur.prev.next = cur.next;cur.next.prev = cur.prev;return;}cur = cur.next;}}

void removeAllKey(int key);

删除所有val = key的节点,这里只需要将remove方法修改以下即可

    public void removeAllKey(int key) {ListNode cur = head;while(cur != null) {if (cur.val == key) {if (cur == head) {head = head.next;if (head == null) {last = null;} else {head.prev = null;}cur = head;continue;}if (cur.next == null) {cur.prev.next = null;last = last.prev;break;}cur.prev.next = cur.next;cur.next.prev = cur.prev;}cur = cur.next;}}

剩下的contains() 、size()、clear()、display()方法和上篇文章的单链表实现方法一致

三、LinkedList类讲解

LinkedList类是Java提供的类,底层是一个双向链表,包含我们刚刚实现过的方法,LinkedList也实现了List接口

3.1 LinkedList构造方法

LinkedList有两个构造方法:

1.无参构造方法

public LinkedList()

2. 带参构造方法

public LinkedList(Collection<? extends E> c)

该构造方法可以将c构造为双向链表,前提是c实现了Collection接口并且其泛型必须是E或是E的子类,例如:

ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);LinkedList<Integer> list = new LinkedList<>(list1); //list1属于ArrayList类,实现了Collection接口,泛型和list1一样都是Integer,此时顺序表list1就被构造为了双向链表list

3.2 LinkedList类常用方法

    boolean add(E e)  //尾插 evoid add(int index, E element)  //将 e 插入到 index 位置boolean addAll(Collection<? extends E> c) //尾插 c 中的元素E remove(int index)  //删除 index 位置元素boolean remove(Object o)  //删除遇到的第一个 oE get(int index) //获取下标 index 位置元素E set(int index, E element) //将下标 index 位置元素设置为 elementvoid clear() //清空链表boolean contains(Object o) //判断 o 是否在线性表中int indexOf(Object o) //返回第一个 o 所在下标int lastIndexOf(Object o) //返回最后一个 o 的下标List<E> subList(int fromIndex, int toIndex) //截取链表,按左闭右开的区间截取[fromIndex, toIndex)

这些方法的底层实现方式和我们上述模拟实现的方法的实现方式相同

3.3 LinkedList遍历

1. for循环

for (int i = 0; i < list.size(); i++) {System.out.print(list.get(i) +" ");
}

2. for-each

for (int x : list) {System.out.print(x +" ");
}

3.迭代器

顺向遍历

ListIterator<Integer> it = list.listIterator();
while(it.hasNext()) {System.out.print(it.next() +" ");
}

逆向遍历

ListIterator<Integer> it1 = list.listIterator(list.size());
while(it1.hasPrevious()) {System.out.print(it1.previous() +" ");
}

🙉本篇文章到此结束,下篇文章会对栈相关知识进行讲解

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

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

相关文章

使用Docker安装Jenkins,并能够在该Jenkins中使用Docker

1. 构建Dockerfile 试错1 参考https://medium.com/manav503/how-to-build-docker-images-inside-a-jenkins-container-d59944102f30 按照文章里所介绍的&#xff0c;实现在Jenkins容器环境中依然能够调用Docker&#xff0c;需要做到以下几步 下载Jenkins镜像将环境中的docke…

项目解决方案:高清视频监控联网设计方案

目 录 一、客户需求 二、网络拓扑图 三、方案描述 四、服务器配置 五、方案优势 1. 多级控制 2. 平台可堆叠使用 3. 支持主流接入协议 4. 多种终端显示 5. 视频质量诊断 6. 客户端功能强大 7. 一机一档 一、客户需求 客户现场存在两个网络环境&#xff0c…

自动化测试CSS元素定位

1.1 CSS定位 1.1.1 绝对路径定位 目标 查找第一个文本为“猜猜看”的a标签 实现 CSS表达式 html>body>div>a[.”猜猜看”] python表达式 driver.find_element_by_css_selector(‘html>body>div>a[.”猜猜看”]’) 1.1.2 相对路径定位 目标 查找第…

【Tomcat与网络1】史前时代—没有Spring该如何写Web服务

在前面我们介绍了网络与Java相关的问题&#xff0c; 最近在调研的时候发现这块内容其实非常复杂&#xff0c;涉及的内容多而且零碎&#xff0c;想短时间梳理出整个体系是不太可能的&#xff0c;所以我们还是继续看Tomcat的问题&#xff0c;后面有网络的内容继续补充吧。 目录 …

MongoDB安装以及卸载

查询id&#xff1a; docker ps [rootlocalhost ~]# docker stop c7a8c4ac9346 c7a8c4ac9346 [rootlocalhost ~]# docker rm c7a8c4ac9346 c7a8c4ac9346 [rootlocalhost ~]# docker rmi mongo sudo docker pull mongo:4.4 sudo docker images 卸载旧的 sudo docker stop mong…

【基础算法】1、快速排序快速选择

快速排序思想&#xff1a; 1、找一个分界点。 2、在分界点两边开始调整范围。 3、递归两边&#xff0c;重复。 例题&#xff1a; 给定你一个长度为 n的整数数列。 请你使用快速排序对这个数列按照从小到大进行排序。 并将排好序的数列按顺序输出。 输入格式 输入共两行&#xf…

【TCP】流量控制和拥塞控制

前言 TCP&#xff08;传输控制协议&#xff09;是互联网协议&#xff08;IP&#xff09;网络传输层协议&#xff0c;负责控制数据包的顺序和流量控制&#xff0c;以防止网络拥塞和数据丢失。TCP流量控制和拥塞控制是确保网络有效通信的重要机制。具体分析如下&#xff1a; 流…

微服务-微服务Alibaba-Nacos 源码分析(上)

Nacos&Ribbon&Feign核心微服务架构图 架构原理 1、微服务系统在启动时将自己注册到服务注册中心&#xff0c;同时外发布 Http 接口供其它系统调用(一般都是基于Spring MVC) 2、服务消费者基于 Feign 调用服务提供者对外发布的接口&#xff0c;先对调用的本地接口加上…

【Java程序设计】【C00168】基于SSM的旅游网管理系统(论文+PPT)

基于SSM的旅游网管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的旅游网系统 本系统分为用户前台功能模块和管理员功能模块2个功能模块。 用户前台功能模块&#xff1a;当游客打开系统的网址后&#xff0c;首先…

【Python笔记-设计模式】单例模式

一、说明 单例是一种创建型设计模式&#xff0c;能够保证一个类只有一个实例&#xff0c; 并提供一个访问该实例的全局节点。 (一) 解决问题 维护共享资源&#xff08;数据库或文件&#xff09;的访问权限&#xff0c;避免多个实例覆盖同一变量&#xff0c;引发程序崩溃。 …

JavaWeb中的Filter(过滤器)和 Listener(监听器)

提示&#xff1a;这两个东西听起来似乎很难&#xff0c;实际上是非常简单的&#xff0c;按照要求写就行了&#xff0c;一定不要被新名词给吓到了。 JavaWeb中的Filter&#xff08;过滤器&#xff09; 一、Filter&#xff08;过滤器&#xff09;1.如何编写 Filter2.Filter 中的细…

最小二乘圆柱拟合(高斯牛顿法)

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 本期话题&#xff1a;最小二乘圆柱拟合 相关背景资料 点击前往 圆柱拟合输入和输出要求 输入 8到50个点&#xff0c;全部采样自圆柱上。每个点3个坐标&#xff0c;坐…

自动化测试的10大误区!

自动化测试因提高效率&#xff0c;减少重复工作的特性而被广泛采用。然而&#xff0c;随着自动化测试的普及&#xff0c;自动化测试也面临一系列挑战和误解。 这些误区不仅影响了测试的有效性&#xff0c;还会导致一定的项目风险&#xff0c;为了确保自动化测试能够真正提升测…

【EI会议征稿通知】2024年第四届激光,光学和光电子技术国际学术会议(LOPET 2024)

2024年第四届激光&#xff0c;光学和光电子技术国际学术会议(LOPET 2024) 2024 4th International Conference on Laser, Optics and Optoelectronic Technology 2024年第四届激光&#xff0c;光学和光电子技术国际学术会议(LOPET 2024)将于2024年5月17日-19日在中国重庆举行。…

长度最小的子数组[中等]

一、题目 给定一个含有n个正整数的数组和一个正整数target。找出该数组中满足其总和大于等于target的长度最小的连续子数组[numsl, numsl1, ..., numsr-1, numsr]&#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回0。 示例 1&#xff1a; 输入&#xff…

迷你型洗衣机好用吗?迷你内裤洗衣机排名前十名推荐

随着大家工作的压力越来越大&#xff0c;下了班之后只能想躺平&#xff0c;在洗完澡之后看着还需要手洗的内衣裤真的很头疼。有些小伙伴还有会攒几天再丢进去洗衣机里面一起&#xff0c;而且这样子是非常不好的&#xff0c;用过的内衣裤长时间不清洗容易滋生细菌&#xff0c;而…

Redis学习——高级篇④

Redis学习——高级篇④ Redis7高级之Redis与Mysql数据双写一致性工程案例&#xff08;四&#xff09; 4.1 MySQL主从复制原理4.2 canal 工作原理4.3 mySQL->canal->redis 双写一致性1.环境2.配置Mysql3.配置canal4. Canal客户端&#xff08;Java编写&#xff0…

JavaScript-for循环的执行顺序

1.目标 掌握for执行顺序 2.实现思路 使用for循环输出0-到5 3.代码实现 Document 4.总结 for执行顺序 1.执行 var i 0 变量初始化 条件判断 是否成立 成立 执行循环体 不成立 退出for循环

STL_list

一、有关list的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个元素和后一个元素。Ii…

Docker容器引擎(6)

目录 一.什么是consul 解决什么问题&#xff1f; consul的模式&#xff1a; 二.consul 部署 consul服务器&#xff1a; 查看版本&#xff1a; 设置代理&#xff0c;在后台启动 consul 服务端&#xff1a; 进行后台启动&#xff1a; 查看集群信息&#xff1a; 访问页面…