数据结构 (JAVA):链表(2)_双向链表(构造、头插、尾插、中间插入、删除等操作及实现代码)

前言

上次,我们介绍了顺序表和单链表的相关概念,以及实现了它们的增加、删除、查找等操作,今天我们介绍另一种链表——双向链表。

一、双向链表

1.1 双向链表的结构:

每个结点存在两个指针域,分别存储该结点的前继结点的引用和后继结点的引用,从任意一个结点出发,都能通过前驱引用以及后继引用完成整个链表结点的遍历。
在这里插入图片描述

1.2 双向链表和单链表的区别:

和单链表改造的循环链表比起来,共同点是这两个结构都能够从任意结点通过不同的操作访问到链表的所有结点。但是双向链表为单链表扩展为在链表中可以进行双向遍历, 换句话说,我们可从链表中第一个节点遍历到到最后一个节点;也可以从最后一个节点遍历到第一个节点。

1.3 实用的场景:

应用场景:单链表适用于解决一条道走到黑的访问场景,比如给正在排队测温的人测量,只需要测试一次就下一位,无需重复测试;循环链表适用于具有环状数据结构的场景,比如丢手绢游戏;双向链表则适合需要提供多个方向访问功能的数据结构,比如老师在考场监考,可以来回走动(假设这个考场座位是顺序的)

二、双向链表的构造和相关操作

2.1 双向链表节点的构造

参考代码:

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;

2.2 节点的插入_前插法

参考代码:

    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;   //重新定义头节点}}

2.2 节点的插入_尾插法

参考代码:

    public void addLast(int data) {ListNode node = new ListNode(data);if (last == null){head = node;last = node;}else {last.next = node;   //先绑定node.prev = last;last =node;   //重新定义尾节点}  }

2.4 返回索引下标的值

参考代码:

    /*** 找到index处的节点* @param index* @return*/private ListNode findIndex(int index){ListNode cur = head;while (index != 0){index--;cur = cur.next;}return cur;}

2.5 指定位置插入节点

插入过程:

  1. node.next = cur;
  2. cur.prev.next = node; //先修改next
  3. node.prev = cur.prev;
  4. cur.prev = node;这里是引用

参考代码:

   /*** 在指定位置插入数据* @param index* @param data*/@Overridepublic void addIndex(int index, int data) {//检查index是否合法int len = size();if(index <0 || index >len){  //判断下标是否合法System.out.println("index不合法 "+ index);}if (index == 0){addFirst(data);return;}if (index == len){addLast(data);return;}ListNode cur = findIndex(index);   // 接收index处的节点ListNode node = new ListNode(data);  //要插入的节点node.next = cur;cur.prev.next = node;   //先修改nextnode.prev = cur.prev;cur.prev = node;}

2.6 是否包含目标值

    public boolean contains(int key) {ListNode cur = head;while (cur != null){if (cur.val == key){return true;}cur = cur.next;}return false;}

2.7 删除节点

主要过程:

  1. cur.prev.next = cur.next;
  2. cur.next.prev = cur.prev;
    这里是引用

参考代码:

  /*** 注意删除key的关键点:* 1、删除头结点和尾节点* 2、只有一个节点* @param key*/@Overridepublic 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;  //正常删除头节点}}else {cur.prev.next = cur.next;if (cur.next == null){//删除的是尾节点last = last.prev;}else {//删除的是中间节点cur.next.prev = cur.prev;}}return;}else {cur = cur.next;}}}

2.8 删除所有关键值得节点

参考代码:

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;  //正常删除头节点}}else {cur.prev.next = cur.next;if (cur.next == null){//删除的是尾节点last = last.prev;}else {//删除的是中间节点cur.next.prev = cur.prev;}}//删除return即可}else {cur = cur.next;}}}

2.8 链表的大小

参考代码:

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

2.9 链表的打印

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

总结

  1. 双向链表在于Link类中,多了一个Pre前驱链接,相对于单链表只有next链接,需要弄清楚前驱和后驱的链接关系

  2. 可以选择固定headt和last节点,插入或者删除first或者last节点,只需要修改2个链接

  3. 在链表中间插入链接,需要修改4个链接(第一步一定是把要插入的节点先连接上);

  4. 在链表中间删除,只需要修改2个链接,一定要通过画图来更好的理解链接的关系。

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

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

相关文章

云服务器租用一年、1个月优惠价格表,阿里/腾讯/京东/华为云

现在租一个服务器多少一个月&#xff1f;优惠价格低至3.8元1个月&#xff0c;租用一个月云服务器收费价格表&#xff1a;阿里云和腾讯云2核2G3M服务器优惠价格61元一年&#xff0c;折合一个月5元&#xff0c;京东云轻量云主机5.8元一个月&#xff0c;华为云服务器优惠价格3.8元…

Linux02(项目部署,手动和自动部署,JDK版本问题,安装软件,安装软件,安装JDK,Tomcat,MySQL,Irzsz)

目录 一、安装软件 1. 安装准备工作 1 Linux里的软件安装方式 2 上传软件到Linux 3 拍照虚拟机快照 2. 安装JDK 1 卸载自带jdk 2 解压JDK 3 配置环境变量 4 测试JDK 3. 安装Tomcat 1 解压Tomcat 2 修改防火墙设置 3 测试Tomcat 启动Tomcat 访问Tomcat 查看Tom…

Arrow, 一个六边形的 Python 时间库

文章目录 Arrow, 一个六边形的 Python 时间库第一部分&#xff1a;背景介绍第二部分&#xff1a;库是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;库函数使用方法第五部分&#xff1a;场景应用第六部分&#xff1a;常见Bug及解决方案第…

NzN的数据结构--归并排序及计数排序

篇接上文&#xff0c;今天要学习的是归并排序以及非比较排序--计数排序。这么励志的日更博主&#xff0c;你怎么能不三连一下呢&#xff1f; 目录 一、归并排序 1. 递归实现 2. 非递归实现 3. 特性总结 二、非比较排序--计数排序 三、排序算法复杂度及稳定性分析 一、归并…

03-JAVA设计模式-责任链模式

责任链模式 什么是责任链模式 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为设计模式&#xff0c;允许你将请求沿着处理者链进行传递。每个处理者均对请求进行某些处理&#xff0c;并可决定是否将请求沿着链传递下去。这种模式给予请求的处理…

Windows版Apache5.7解压直用(免安装-绿色-项目打包直接使用)

windows下Apache分类 Apache分为 安装版和解压版 安装版: 安装方便&#xff0c;下一步------下一步就OK了&#xff0c;但重装系统更换环境又要重新来一遍&#xff0c;会特别麻烦 解压版&#xff08;推荐&#xff09;&#xff1a; 这种方式&#xff08;项目打包特别方便&#…

String类中常见面试题

1.string类属于基本类型吗&#xff1f; string类不是基本类型&#xff1b;它属于引用数据类型 2.操作字符串的类有哪些?有什么区别&#xff1f; 有三种&#xff1a;string,stringBuilder,stringBuffer 区别&#xff1a; String:不可变类&#xff0c;字符串一旦被创建就不能…

给你的AppImage创建桌面快捷方式

原文链接 https://www.cnblogs.com/HGNET/p/16396589.html 运行环境:Ubuntu 22.04 LTS 1.首先准备好AppImage文件并放在一个你知道的地方 2.打开终端&#xff0c;在/usr/share/applications下新建APP.desktop文件&#xff08;APP可以改成你的应用名称&#xff09; cd /usr/s…

【C++算法竞赛 · 图论】图的存储

前言 图的存储 邻接矩阵 方法 复杂度 应用 例题 题解 邻接表 方法 复杂度 应用 前言 上一篇文章中&#xff08;【C算法竞赛 图论】图论基础&#xff09;&#xff0c;介绍了图论相关的概念和一种图的存储的方法&#xff0c;这篇文章将会介绍剩下的两种方法&#xff…

Sonatype Nexus 服务器迁移

因为服务器的升级和调整&#xff0c;有时候会对安装 Sonatype Nexus 的服务器进行迁移到新服务器上。 从技术架构上来说&#xff0c;Sonatype Nexus 我们使用的是 AWS 的存储&#xff0c;所以我们并不需要拷贝大量的数据。 文件夹结构 在备份和恢复之前&#xff0c;我们需要…

【C++】为什么需要CMake?

文章目录 Cmake是什么&#xff1f;Cmake是怎么出现的&#xff1f;C语言为什么会有头文件&#xff1f;C程序的编译流程C程序编译演化史 Cmake是什么&#xff1f; 很多C小白刚进入公司开始接触业务代码的时候&#xff0c;或者在学校实验室接触一些大型的C项目的时候&#xff0c;…

MATLAB 自定义实现点云法向量和曲率计算(详细解读)(64)

MATLAB 自定义实现点云法向量和曲率计算(详细解读)(64) 一、算法介绍二、算法步骤三、算法实现1.代码 (完整,注释清晰,可直接用)2.结果一、算法介绍 首先说明: ------这里代码手动实现,不调用matlab提供的法向量计算接口,更有助于大家了解法向量和曲率的计算方法,…