03双向链表

双向链表

单向链表的缺点

  1. 单向链表,只能是一个方向来查找,而双向链表可以向前或者向后查找。
  2. 单向链表不能自我删除,需要靠辅助结点。而双向链表可以自我删除。所以我们单链表删除结点的时候,总要找到temp(待删除结点的前一个结点)的下一个结点来完成删除操作。
单向链表结点示意图

在这里插入图片描述

双向链表逻辑图

在这里插入图片描述

双向链表的遍历、添加、修改、删除操作

遍历

与单向链表一样,可以向前也可以向后遍历。

添加

添加在最后

  1. 找到链表的最后一个结点temp
  2. temp.next = newNode;
  3. newNode.pre = temp;

在中间添加(需要考虑指针变动顺序)

  1. 找到要添加的前一个结点temp
  2. newNode.next = temp.next
  3. temp.next.pre = newNode
  4. newNode.pre = temp
  5. temp.next = newNode

在这里插入图片描述

修改

思路与单向链表的一致

删除
  1. 因为是双向链表,所以可以实现自我删除
  2. 直接找到这个这个结点,temp
  3. temp.pre.next = temp.next
  4. temp.next.pre = temp.pre

代码实现

package com.linkedlist;public class DoubleLinkedListDemo {public static void main(String[] args) {System.out.println("======双向链表的测试=======");HeroNode2 hero1 = new HeroNode2(1, "1", "1");HeroNode2 hero2 = new HeroNode2(2, "2", "2");HeroNode2 hero3 = new HeroNode2(3, "3", "3");HeroNode2 hero4 = new HeroNode2(4, "4", "4");HeroNode2 hero5 = new HeroNode2(5, "5", "5");DoubleLinkedList doubleLinkedList = new DoubleLinkedList();//添加doubleLinkedList.addNode(hero1);doubleLinkedList.addNode(hero2);doubleLinkedList.addNode(hero3);doubleLinkedList.addNode(hero4);doubleLinkedList.addNode(hero5);doubleLinkedList.showList();//修改System.out.println("========修改四号结点信息========");doubleLinkedList.updateNode(new HeroNode2(4, "04", "04"));doubleLinkedList.showList();//删除System.out.println("========删除3号结点信息=======");doubleLinkedList.deleteNode(3);doubleLinkedList.showList();//按顺序添加System.out.println("=========按顺序添加==========");DoubleLinkedList doubleLinkedList1 = new DoubleLinkedList();doubleLinkedList1.addNodeByOrder(new HeroNode2(4,"4","4"));doubleLinkedList1.addNodeByOrder(new HeroNode2(3,"3","3"));doubleLinkedList1.addNodeByOrder(new HeroNode2(1,"1","1"));doubleLinkedList1.addNodeByOrder(new HeroNode2(1,"1","1"));doubleLinkedList1.addNodeByOrder(new HeroNode2(2,"2","2"));doubleLinkedList1.addNodeByOrder(new HeroNode2(5,"5","5"));doubleLinkedList1.showList();}
}class DoubleLinkedList {private HeroNode2 head = new HeroNode2(0, "", "");public HeroNode2 getHead() {return head;}//遍历双向链表public void showList() {/*** 1. 判断链表是否为空。* 2. 因为头结点不能动,所以拷贝一份。temp*/if (head.next == null) {System.out.println("当前链表为空");return;}//因为头结点没有使用,所以第一个显示的结点就是head.nextHeroNode2 temp = head.next;while (temp != null) {System.out.println(temp);temp = temp.next;//变量后移}}//添加结点public void addNode(HeroNode2 hero) {//找到最后一个结点//因为head结点不能用,所以先拷贝一份HeroNode2 temp = head;while (true) {//最后一个结点特点,结点的next属性值为nullif (temp.next == null) {break;}temp = temp.next;//指针后移}//形成双向链表temp.next = hero;hero.pre = temp;}//修改  与双向链表一致public void updateNode(HeroNode2 newHero) {/*** 思路* 1. 判断是否为空* 2. 找到需要修改的结点*/if (head.next == null) {System.out.println("链表为空,不满足修改条件");return;}HeroNode2 temp = head;boolean flag = false;while (true) {if (temp == null) {      //遍历完了都没有找到break;//已经遍历结束了}if (temp.no == newHero.no) {flag = true;break;}temp = temp.next;}if (flag) {temp.name = newHero.name;temp.nickName = newHero.nickName;} else {System.out.printf("没有找到 编号为 %d 的结点信息,不能修改\n", newHero.no);}}//删除结点 -- 通过英雄编号,即hero.no/*** 思路:* 1. 我们先找到自己* 2. 自我删除* 3. 被删除的结点,将不会有其它引用指向,剩下的交给java的垃圾回收机制。*/public void deleteNode(int no) {HeroNode2 temp = head.next;boolean flag = false;while (true) {//已经到链表的最后了,还没有找到if (temp == null) {break;}//找到的情况if (temp.no == no) {flag = true;break;}temp = temp.next;}//业务处理if (flag) {//自我删除temp.pre.next = temp.next;//如果删除最后一个结点是没有if (temp.next != null) {temp.next.pre = temp.pre;}System.out.printf("成功删除编号为 %d 的结点\n", no);} else {System.out.printf("没有找到编号为 %d 的结点\n", no);}}//根据序号来添加。public void addNodeByOrder(HeroNode2 hero) {//同理,做一个拷贝HeroNode2 temp = head;boolean flag = false; //添加的编号是否存在//这个指针要找到添加位置的前一个结点。while (true) {if (temp.next == null) {break;//如果此时就是最后一个结点}//下面这两个顺序不能交换,一定是先判断是否存在再判断下一个编号是否大if (temp.no == hero.no) {flag = true;//此时已经存在了break;}if (temp.next.no > hero.no) {break;//位置找到了在这个后面添加}temp = temp.next;}if (flag) {System.out.printf("准备加入的英雄%d  %s已经存在了,不能添加\n", hero.no, hero.name);} else {//插入到temp后面 -- 这个顺序不能搞错了。if (temp.next != null){hero.next = temp.next;temp.next.pre = hero;hero.pre = temp;temp.next = hero;}else {addNode(hero);}}}
}class HeroNode2 {public int no;public String name;public String nickName;public HeroNode2 next;public HeroNode2 pre;//构造器public HeroNode2(int no, String name, String nickName) {this.no = no;this.name = name;this.nickName = nickName;}@Overridepublic String toString() {return "HeroNode2{" +"no=" + no +", name='" + name + '\'' +", nickName='" + nickName + '\'' +'}';}
}

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

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

相关文章

空间曲线的切线和法平面与曲面的切平面和法线

(一)空间曲线的切线和法平面 1. 参数方程的形式 理解和记忆如下公式: 参数方程在知道偏导数的情况下,得到该点的切线以及法平面的公式,笔者可以理解但是无法证明。 2. 可以转换为参数方程的第二种形式&#xff1a…

从入门到精通:解锁Linux开发工具和编译器的力量

目录 一.编辑器vim的使用1.vim的基本概念2.vim的使用二.编译器gcc/g1.编译器的使用2.编译器是如何完成的?3.动态库与静态库 一.编辑器vim的使用 1.vim的基本概念 vim是一个方便编程的功能特别丰富的文本编辑器,凭借他简洁的三种模式以及丰富的快捷键操…

MySQL进阶SQL语句(二)

MySQL进阶SQL语句(二) 一、MySQL进阶SQL语句1.1 连接查询1.2 CREATE VIEW视图,可以被当作是虚拟表或存储查询1.3 UNION 联集1.4 CASE1.5 空值(NULL) 和 无值() 的区别1.6 正则表达式 二、存储过程2.1 存储过程定义2.2 存储过程的优点2.3 存储…

PySpark如何输入数据到Spark中?【RDD对象】

PySpark支持多种数据的输入,在输入完成后,都会得到一个:RDD类的对象RDD全称为弹性分布式数据集(Resilient Distributed Datasets),PySpark针对数据的处理,都是以RDD对象作为载体,即: •数据存储…

java面试Day13

1. 有哪些注解可以注入 Bean?Autowired 和 Resource 的区别? 在 Spring 框架中,常用的注入 Bean 的注解包括: Autowired:自动注入,按照类型自动装配,如果有多个同类型的 Bean,则需要…

手撕code(3)

文章目录 迷宫最短路径和输出深度优先广度优先 48 旋转矩阵图像大数加减法146 LRU 缓存算法460 LFU 缓存算法 迷宫最短路径和输出 给定一个 n m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1 ,其中 0 表示可以走的路,1…

软考A计划-系统集成项目管理工程师-项目整体管理-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 👉关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

SurfaceFlinge/InputFlinger分析-android画面缩放后依然点击正常原理分析

hi,粉丝朋友们: 这两天刚好在做自由窗口相关国内需求,刚好遇到一个疑惑,那就是画面进行缩放后发现依然触摸画面可以正常反映问题。 具体疑惑背景 疑问点如下: 坐标是针对屏幕的,按钮也是相对Activity的&…

深蓝学院C++基础与深度解析笔记 第 9 章 序列与关联容器

第 9 章 序列与关联容器 1. 容器概述 A、容器: 一种特殊的类型,其对象可以放置其它类型的对象(元素) – 需要支持的操作:对象的添加、删除、索引、遍历 – 有多种算法可以实现容器,每种方法各有利弊B、容…

Redis的高可用与持久化

目录 一、Redis 高可用1. 持久化2. 主从复制3. 哨兵4. 集群(cluster) 二、Redis 持久化方式1. 持久化的功能2. 持久化的方式 三、RDB 持久化1. 触发条件2.执行流程3. 启动时加载 四、AOF持久化1.开启 AOF2. 执行流程2.1 命令追加2.2 文件写入(write)和文…

【机器学习】——续上:卷积神经网络(CNN)与参数训练

目录 引入 一、CNN基本结构 1、卷积层 2、下采样层 3、全连接层 二、CNN参数训练 总结 引入 卷积神经网络(CNN)是一种有监督深度模型框架,尤其适合处理二维数据问题,如行人检测、人脸识别、信号处理等领域,是带…

threejs动画

个人博客地址: https://cxx001.gitee.io 前面我们所用的模型大都是静态的,没有动画,没有生命。这节我们将赋予它们生命。 动画本质是通过改变物体的旋转、缩放、位置、材质、顶点、面以及其它你所能想到的属性来实现的。这些其实在前面章节示例里或多或…