链表(Linked List)之双向链表

双向链表应用实例

使用带head头的双向链表实现 –水浒英雄排行榜

管理单向链表的缺点分析:

单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。

单向链表不能自我删除,需要靠辅助节点 ,而双向链表,则可以自我删除,所以前面我们单链表删除时节点,总是找到temp,temp是待删除节点的前一个节点(认真体会).

示意图帮助理解删除

哔哩哔哩动画

课堂作业和思路提示:双向链表的第二种添加方式,按照编号顺序 [示意图] 按照单链表的顺序添加,稍作修改即可.

img

分析 双向链表的遍历,添加,修改,删除的操作思路 ===》代码实现

  1. 遍历 方和 单链表一样,只是可以向前,也可以向后查找 2) 添加 (默认添加到双向链表的最后)
- (1) 先找到双向链表的最后这个节点
- (2) temp.next = newHeroNode
- (3) newHeroNode.pre = temp;
  1. 修改 思路和 原来的单向链表一样. 4) 删除
- (1) 因为是双向链表,因此,我们可以实现自我删除某个节点
- (2) 直接找到要删除的这个节点,比如temp
- (3)  temp.pre.next = temp.next
- (4) temp.next.pre = temp.pre;

代码实现

package com.atguigu.linkedlist;/*** ClassName:  <br/>* Description:  <br/>* Date: 2021-02-19 14:32 <br/>* @project data_algorithm* @package com.atguigu.linkedlist*/
public class DoubleLinkedListDemo {public static void main(String[] args) {// 测试System.out.println("双向链表的测试");// 先创建节点HeroNode2 hero1 = new HeroNode2(1, "宋江", "及时雨");HeroNode2 hero2 = new HeroNode2(2, "卢俊义", "玉麒麟");HeroNode2 hero3 = new HeroNode2(3, "吴用", "智多星");HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头");// 创建一个双向链表DoubleLinkedList doubleLinkedList = new DoubleLinkedList();doubleLinkedList.add(hero1);doubleLinkedList.add(hero2);doubleLinkedList.add(hero3);doubleLinkedList.add(hero4);doubleLinkedList.list();// 修改HeroNode2 newHeroNode = new HeroNode2(4, "公孙胜", "入云龙");doubleLinkedList.update(newHeroNode);System.out.println("修改后的链表情况");doubleLinkedList.list();// 删除doubleLinkedList.del(3);System.out.println("删除后的链表情况~~");doubleLinkedList.list();}}// 创建一个双向链表的类
class DoubleLinkedList {// 先初始化一个头节点, 头节点不要动, 不存放具体的数据private HeroNode2 head = new HeroNode2(0, "", "");// 返回头节点public HeroNode2 getHead() {return head;}// 遍历双向链表的方法// 显示链表[遍历]public void list() {// 判断链表是否为空if (head.next == null) {System.out.println("链表为空");return;}// 因为头节点,不能动,因此我们需要一个辅助变量来遍历HeroNode2 temp = head.next;while (true) {// 判断是否到链表最后if (temp == null) {break;}// 输出节点的信息System.out.println(temp);// 将temp后移, 一定小心temp = temp.next;}}// 添加一个节点到双向链表的最后.public void add(HeroNode2 heroNode) {// 因为head节点不能动,因此我们需要一个辅助遍历 tempHeroNode2 temp = head;// 遍历链表,找到最后while (true) {// 找到链表的最后if (temp.next == null) {//break;}// 如果没有找到最后, 将将temp后移temp = temp.next;}// 当退出while循环时,temp就指向了链表的最后// 形成一个双向链表temp.next = heroNode;heroNode.pre = temp;}// 修改一个节点的内容, 可以看到双向链表的节点内容修改和单向链表一样// 只是 节点类型改成 HeroNode2public void update(HeroNode2 newHeroNode) {// 判断是否空if (head.next == null) {System.out.println("链表为空~");return;}// 找到需要修改的节点, 根据no编号// 定义一个辅助变量HeroNode2 temp = head.next;boolean flag = false; // 表示是否找到该节点while (true) {if (temp == null) {break; // 已经遍历完链表}if (temp.no == newHeroNode.no) {// 找到flag = true;break;}temp = temp.next;}// 根据flag 判断是否找到要修改的节点if (flag) {temp.name = newHeroNode.name;temp.nickname = newHeroNode.nickname;} else { // 没有找到System.out.printf("没有找到 编号 %d 的节点,不能修改\n", newHeroNode.no);}}// 从双向链表中删除一个节点,// 说明// 1 对于双向链表,我们可以直接找到要删除的这个节点// 2 找到后,自我删除即可public void del(int no) {// 判断当前链表是否为空if (head.next == null) {// 空链表System.out.println("链表为空,无法删除");return;}HeroNode2 temp = head.next; // 辅助变量(指针)boolean flag = false; // 标志是否找到待删除节点的while (true) {if (temp == null) { // 已经到链表的最后break;}if (temp.no == no) {// 找到的待删除节点的前一个节点tempflag = true;break;}temp = temp.next; // temp后移,遍历}// 判断flagif (flag) { // 找到// 可以删除// temp.next = temp.next.next;[单向链表]temp.pre.next = temp.next;// 这里我们的代码有问题?// 如果是最后一个节点,就不需要执行下面这句话,否则出现空指针if (temp.next != null) {temp.next.pre = temp.pre;}} else {System.out.printf("要删除的 %d 节点不存在\n", no);}}}// 定义HeroNode2 , 每个HeroNode 对象就是一个节点
class HeroNode2 {public int no;public String name;public String nickname;public HeroNode2 next; // 指向下一个节点, 默认为nullpublic HeroNode2 pre; // 指向前一个节点, 默认为null// 构造器public HeroNode2(int no, String name, String nickname) {this.no = no;this.name = name;this.nickname = nickname;}// 为了显示方法,我们重新toString@Overridepublic String toString() {return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";}}

原文链接:传送门

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

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

相关文章

H264 解码耗时分析

在数字基带处理器上代码的最佳放置 美国模拟器件公司 Jose Fridman   在手机等嵌入式系统中&#xff0c;除了处理器执行时间外&#xff0c;最重要的资源就是设备总线和存储器接口。本文将介绍一种在使用指令高速缓存时其带宽消耗的基础上&#xff0c;统计分析高速缓存所采用…

链表(Linked List)之环形链表

原文地址:传送门 单向环形链表应用场景 Josephu(约瑟夫、约瑟夫环) 问题 Josephu 问题为&#xff1a;设编号为1&#xff0c;2&#xff0c;… n的n个人围坐一圈&#xff0c;约定编号为k&#xff08;1<k<n&#xff09;的人从1开始报数&#xff0c;数到m 的那个人出列&…

免费SSL证书(支持1.0、1.1、1.2)

由于公司要开发微信小程序&#xff0c;而微信小程序的接口需要https协议的&#xff0c;并且要支持TLS1.0、TLS1.1、TLS1.2。如果仅仅是为了开发小程序&#xff0c;安全等级又不用太高&#xff0c;可以选择免费的SSL证书 在这里选择腾讯云的证书&#xff0c;申请在 https://cons…

使用栈来完成一个表达式的结果

原文地址:传送门 使用栈来完成一个表达式的结果 使用栈完成计算 一个表达式的结果 7*2*2-51-53-4 &#xff1f; 32*6-2[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XzPnJzRe-1614845779689)(https://victorfengming.gitee.io/data_algorithm/i…

Python 关于bytes类方法对数字转换的误区, Json的重要性

本文起源于一次犯错, 在发觉bytes()里面可以填数字, 转出来的也是bytes类型, 就心急把里面的东西decode出来. 结果为空.搞来搞去以为是命令不熟练事实上错在逻辑.a1 bytes(11, encodingutf-8) print(a1)b1 a1.decode()print(b1)a2 bytes(11) print(a2)b2 a2.decode() print…

psnr 计算

PSNR是“Peak Signal to Noise Ratio”的缩写&#xff0c;峰值信噪比。psnr一般是用于最大值信号和背景噪音之间的一个工程项目。 PSNR计算公式如下&#xff1a; 8bits表示法中&#xff0c;peak的最大值为255&#xff1b;MSE指Mean Square Error&#xff08;均方误差&#xff0…

光源时间_缩短背光源的使用寿命的原因

许多场所都会使用到led这种产品&#xff0c;这种产品经常用于背光的照亮中。但是由于使用led的局限性较大&#xff0c;所以led逐渐被背光源这种产品所代替&#xff0c;常常用于背景的照亮让宣传图可以展现出更好的视觉&#xff0c;这也是许多人选择背光源的原因。那么&#xff…

递归应用场景和调用机制

原文链接:传送门 递归 迷宫问题(回溯) 概念 简单呐的说: 递归就是方法自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂的问题,同时让代码变得简洁. 案例-递归调用机制 打印问题 public static void test(int n){if(n>2){test(n-1);}System.out.print…

八皇后问题分析与Java实现

原文链接:传送门 八皇后问题 八皇后问题&#xff0c;是一个古老而著名的问题&#xff0c;是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯贝瑟尔于1848年提出&#xff1a;在88格的国际象棋上摆放八个皇后&#xff0c;使其不能互相攻击&#xff0c;即&#xff1a;任意两个…

单例模式之恶汉模式(详解)

一.设计模式 概念&#xff1a;设计模式是一套被反复使用、多人知晓的、经过分类编目的、代码设计经验的总结。 目的&#xff1a;是用设计模式可以重用代码&#xff0c;让代码更容易被他人理解&#xff0c;保证代码的可靠性。 二.为什么要使用单例模式&#xff1f; 如果创造出多…

迷宫回溯问题分析和实现

原文链接:传送门 迷宫问题 说明: 小球得到的路径&#xff0c;和程序员设置的找路策略有关即&#xff1a;找路的上下左右的顺序相关再得到小球路径时&#xff0c;可以先使用(下右上左)&#xff0c;再改成(上右下左)&#xff0c;看看路径是不是有变化测试回溯现象思考: 如何求出…

canvas clear 指定属性的元素_好程序员web前端分享CSS属性组成及作用

好程序员web前端分享CSS属性组成及作用学习目标1、css属性和属性值的定义2、css文本属性3、css列表属性4、css背景属性5、css边框属性6、css浮动属性一、css属性和属性值的定义属性&#xff1a;属性是指定选择符所具有的属性&#xff0c;它是css的核心&#xff0c;css2共有150多…

排序算法介绍和分类

原文链接:传送门 排序算法的介绍 排序也成排序算法 排序也称排序算法(Sort Algorithm)&#xff0c;排序是将一组数据&#xff0c;依指定的顺序进行排列的过程。 排序的分类&#xff1a; 1) 内部排序: 指将需要处理的所有数据都加载到**内部存储器(内存)**中进行排序。 2) 外…

认识高清视频编码(MPEG、H.264、WMV-HD、RMVB)

文章出处&#xff1a;www.net1980.com 原创 最近两年&#xff0c;“高清”这个词语非常火热&#xff0c;已经成为家电和IT行业的最新潮流了。高清视频和普通视频有什么区别呢&#xff1f;主要是分辨率上的区别&#xff0c;720P视频的分辨率为1280X720&#xff0c;1080P视频的分…

解读SPP / SPPF / SimSPPF / ASPP / RFB / SPPCSPC

SPP与SPPF 一、SPP的应用的背景 在卷积神经网络中我们经常看到固定输入的设计&#xff0c;但是如果我们输入的不能是固定尺寸的该怎么办呢&#xff1f; 通常来说&#xff0c;我们有以下几种方法&#xff1a; &#xff08;1&#xff09;对输入进行resize操作&#xff0c;让他们…

go mongodb排序查询_《MongoDB》day two

Mongodb的更新方式有&#xff1f;db.集合名.update() 函数:用于更新已存在的文档。语法格式&#xff1a;db.COLLECTION_NAME.update({查询条件},{更新内容},{更新参数(可选)}) 注&#xff1a;这种方式会覆盖原有的文档。使用更新操作符 使用 save()函数更新文档 Mongodb的updat…

哈希表思路图解和代码实现

原文链接传送门 哈希表(散列)-Google上机题 看一个实际需求&#xff0c;google公司的一个上机题: 有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址…),当输入该员工的id时,要求查找到该员工的 所有信息. 要求: 不使用数据库,尽量节省内存,速度越…

glibc交叉编译_TSN之linuxptp交叉编译

0 开发环境1 linuxptp是什么2 为什么要交叉编译linuxptp3 修改makefile4 修改源码5 交叉编译0 开发环境笔记本&#xff1a;ubuntu18.04.5&#xff0c;内核版本为5.3 开发板&#xff1a;imx8mp-evk内核版本&#xff1a;Linux5.4.24交叉编译工具链&#xff1a;fsl-imx-xwayland-g…

声音编码

1.脉冲编码调制PCM文件格式简介 将音频数字化&#xff0c;其实就是将声音数字化。最常见的方式是透过脉冲编码调制PCM(Pulse Code Modulation) 。运作原理如下。首先我们考虑声音经过麦克风&#xff0c;转换成一连串电压变化的信号&#xff0c;如图一所示。这张图的横座标为秒&…

Elastic Stack简介

Elastic Stack简介 如果你没有听说过Elastic Stack&#xff0c;那你一定听说过ELK&#xff0c;实际上ELK是三款软件的简称&#xff0c;分别是Elasticsearch、 Logstash、Kibana组成&#xff0c;在发展的过程中&#xff0c;又有新成员Beats的加入&#xff0c;所以就形成了Elast…