第 4 章 链表(1)

4.1链表(Linked List)介绍

链表是有序的列表,但是它在内存中是存储如下

在这里插入图片描述
小结:

  1. 链表是以节点的方式来存储,是链式存储
  2. 每个节点包含 data 域, next 域:指向下一个节点.
  3. 如图:发现链表的各个节点不一定是连续存储.
  4. 链表分带头节点的链表没有头节点的链表,根据实际的需求来确定

单链表(带头结点) 逻辑结构示意图如下
在这里插入图片描述

4.2单链表的应用实例

使用带head头的单向链表实现 –水浒英雄排行榜管理
完成对英雄人物的增删改查操作, 注: 删除和修改,查找可以考虑学员独立完成,也可带学员完成

1) 第一种方法在添加英雄时,直接添加到链表的尾部

思路分析示意图:
在这里插入图片描述

2) 第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)

在这里插入图片描述

3) 修改节点功能

思路
(1) 先找到该节点,通过遍历,
(2) tempname = newHeroNode.name ;
temp.nickname= newHeroNode.nickname

4) 删除节点

思路分析的示意图:
在这里插入图片描述

5.代码演示

1-单链表创建和遍历的分析实现

/*** 单链表*/
public class SingleLinkedListDemo {public static void main(String[] args) {//进行测试//先创建节点HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");//创建链表SingleLinkedList linkedList = new SingleLinkedList();linkedList.add(hero1);linkedList.add(hero2);linkedList.add(hero3);linkedList.add(hero4);//显示linkedList.list();}
}//定义SingleLinkedList 管理我们的英雄
class SingleLinkedList {//先初始化一个头节点,头节点不要动,不存放具体的数据private HeroNode head = new HeroNode(0, "", "");//添加节点到单向链表//思路:当不考虑编号顺序时//1.找到当前链表的最后节点//2.将最后这个节点的next 指向 新的节点public void add(HeroNode heroNode) {//因为head节点不能动,因此我们需要一个辅助遍历 tempHeroNode temp = head;while (true) {//找到链表的最后if (temp.next == null) {break;}//如果没有找到最后,将temp后移temp = temp.next;}//当退出while循环时,temp就指向了链表的最后//将最后这个节点的next 指向 新的节点temp.next = heroNode;}//显示链表【遍历】public void list() {//判断链表是否为空if (head.next == null) {System.out.println("链表为空");return;}//因为头节点,不能动,因此我们需要一个辅助遍历来遍历HeroNode temp = head.next;while (true) {//判断是否到链表最后if (temp == null) {break;}//输出节点的信息System.out.println(temp);//将temp后移,一定小心temp = temp.next;}}
}//定义HeroNode,每个HeroNode 对象就是一个节点
class HeroNode {private int no;private String name;private String nickName;public HeroNode next;//指向下一个节点//构造器public HeroNode(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 + '\'' +'}';//删除next打印的原因是因为,节点的下一个节点,有连着节点,所以删除/*return "HeroNode{" +"no=" + no +", name='" + name + '\'' +", nickName='" + nickName + '\'' +", next=" + next +'}';*/}
}
HeroNode{no=1, name='宋江', nickName='及时雨'}
HeroNode{no=2, name='卢俊义', nickName='玉麒麟'}
HeroNode{no=3, name='吴用', nickName='智多星'}
HeroNode{no=4, name='林冲', nickName='豹子头'}

2-单链表按顺序插入节点


/*** 单链表*/
public class SingleLinkedListDemo {public static void main(String[] args) {//进行测试//先创建节点HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");//创建链表SingleLinkedList linkedList = new SingleLinkedList();linkedList.addByOrder(hero2);linkedList.addByOrder(hero3);linkedList.addByOrder(hero1);linkedList.addByOrder(hero4);//显示linkedList.list();}
}//定义SingleLinkedList 管理我们的英雄
class SingleLinkedList {//先初始化一个头节点,头节点不要动,不存放具体的数据private HeroNode head = new HeroNode(0, "", "");//第二种方式在添加英雄时,根据排名将英雄插入到指定位置// (如果有这个排名,则添加失败,并给出提示)public void addByOrder(HeroNode heroNode){//因为头节点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置//因为单链表,因为我们找的temp 是位于 添加位置的前一个节点,否则插入不了HeroNode temp = head;boolean flag= false;//flag,标识添加的编号是否存在,默认为falsewhile (true){if (temp.next == null){//说明temp已经在链表的最后break;}if (temp.next.no > heroNode.no){//位置找到,就在temp的后面插入break;}else if (temp.next.no == heroNode.no){//说明希望添加的heroNode的编号已经存在flag = true;break;}temp = temp.next;//后移,遍历当前链表}//判断flag的值if (flag){System.out.printf("准备插入的英雄的编号 %d 已经存在了,不能加入\n", heroNode.no);}else {//插入到链表中,temp的后面heroNode.next = temp.next;temp.next = heroNode;}}//显示链表【遍历】public void list() {//判断链表是否为空if (head.next == null) {System.out.println("链表为空");return;}//因为头节点,不能动,因此我们需要一个辅助遍历来遍历HeroNode temp = head.next;while (true) {//判断是否到链表最后if (temp == null) {break;}//输出节点的信息System.out.println(temp);//将temp后移,一定小心temp = temp.next;}}
}//定义HeroNode,每个HeroNode 对象就是一个节点
class HeroNode {public int no;public String name;public String nickName;public HeroNode next;//指向下一个节点//构造器public HeroNode(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 + '\'' +'}';}
}
HeroNode{no=1, name='宋江', nickName='及时雨'}
HeroNode{no=2, name='卢俊义', nickName='玉麒麟'}
HeroNode{no=3, name='吴用', nickName='智多星'}
HeroNode{no=4, name='林冲', nickName='豹子头'}

3-单链表节点的修改


/*** 单链表*/
public class SingleLinkedListDemo {public static void main(String[] args) {//进行测试//先创建节点HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");//创建链表SingleLinkedList linkedList = new SingleLinkedList();//链表排序linkedList.addByOrder(hero2);linkedList.addByOrder(hero3);linkedList.addByOrder(hero1);linkedList.addByOrder(hero4);//显示linkedList.list();System.out.println("\n修改后的链表:");HeroNode updhero2 = new HeroNode(2, "小卢", "小旺旺");linkedList.update(updhero2);//显示linkedList.list();}
}//定义SingleLinkedList 管理我们的英雄
class SingleLinkedList {//先初始化一个头节点,头节点不要动,不存放具体的数据private HeroNode head = new HeroNode(0, "", "");//添加节点到单向链表//思路:当不考虑编号顺序时//1.找到当前链表的最后节点//2.将最后这个节点的next 指向 新的节点public void add(HeroNode heroNode) {//因为head节点不能动,因此我们需要一个辅助遍历 tempHeroNode temp = head;while (true) {//找到链表的最后if (temp.next == null) {break;}//如果没有找到最后,将temp后移temp = temp.next;}//当退出while循环时,temp就指向了链表的最后//将最后这个节点的next 指向 新的节点temp.next = heroNode;}//第二种方式在添加英雄时,根据排名将英雄插入到指定位置// (如果有这个排名,则添加失败,并给出提示)public void addByOrder(HeroNode heroNode) {//因为头节点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置//因为单链表,因为我们找的temp 是位于 添加位置的前一个节点,否则插入不了HeroNode temp = head;boolean flag = false;//flag,标识添加的编号是否存在,默认为falsewhile (true) {if (temp.next == null) {//说明temp已经在链表的最后break;}if (temp.next.no > heroNode.no) {//位置找到,就在temp的后面插入break;} else if (temp.next.no == heroNode.no) {//说明希望添加的heroNode的编号已经存在flag = true;break;}temp = temp.next;//后移,遍历当前链表}//判断flag的值if (flag) {System.out.printf("准备插入的英雄的编号 %d 已经存在了,不能加入\n", heroNode.no);} else {//插入到链表中,temp的后面heroNode.next = temp.next;temp.next = heroNode;}}//修改节点的信息,根据no编号来修改,即no编号不能改//说明//1.根据 newHeroNode 的 no 来修改即可public void update(HeroNode newHeroNode) {//判断是否为空if (head.next == null) {System.out.println("链表为空");return;}//找到需要修改的节点,根据no编号//定义一个辅助变量HeroNode 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);}}//显示链表【遍历】public void list() {//判断链表是否为空if (head.next == null) {System.out.println("链表为空");return;}//因为头节点,不能动,因此我们需要一个辅助遍历来遍历HeroNode temp = head.next;while (true) {//判断是否到链表最后if (temp == null) {break;}//输出节点的信息System.out.println(temp);//将temp后移,一定小心temp = temp.next;}}
}//定义HeroNode,每个HeroNode 对象就是一个节点
class HeroNode {public int no;public String name;public String nickName;public HeroNode next;//指向下一个节点//构造器public HeroNode(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 + '\'' +'}';}
}
HeroNode{no=1, name='宋江', nickName='及时雨'}HeroNode{no=2, name='卢俊义', nickName='玉麒麟'}HeroNode{no=3, name='吴用', nickName='智多星'}
HeroNode{no=4, name='林冲', nickName='豹子头'}修改后的链表:
HeroNode{no=1, name='宋江', nickName='及时雨'}HeroNode{no=2, name='小卢', nickName='小旺旺'}HeroNode{no=3, name='吴用', nickName='智多星'}
HeroNode{no=4, name='林冲', nickName='豹子头'}

4-单链表节点的删除和小计


/*** 单链表*/
public class SingleLinkedListDemo {public static void main(String[] args) {//进行测试//先创建节点HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");HeroNode hero3 = new HeroNode(3, "吴用", "智多星");HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");//创建链表SingleLinkedList linkedList = new SingleLinkedList();//链表排序linkedList.addByOrder(hero2);linkedList.addByOrder(hero3);linkedList.addByOrder(hero1);linkedList.addByOrder(hero4);//显示linkedList.list();System.out.println("\n删除后的节点:");linkedList.del(1);linkedList.list();}
}//定义SingleLinkedList 管理我们的英雄
class SingleLinkedList {//先初始化一个头节点,头节点不要动,不存放具体的数据private HeroNode head = new HeroNode(0, "", "");//添加节点到单向链表//思路:当不考虑编号顺序时//1.找到当前链表的最后节点//2.将最后这个节点的next 指向 新的节点public void add(HeroNode heroNode) {//因为head节点不能动,因此我们需要一个辅助遍历 tempHeroNode temp = head;while (true) {//找到链表的最后if (temp.next == null) {break;}//如果没有找到最后,将temp后移temp = temp.next;}//当退出while循环时,temp就指向了链表的最后//将最后这个节点的next 指向 新的节点temp.next = heroNode;}//第二种方式在添加英雄时,根据排名将英雄插入到指定位置// (如果有这个排名,则添加失败,并给出提示)public void addByOrder(HeroNode heroNode) {//因为头节点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置//因为单链表,因为我们找的temp 是位于 添加位置的前一个节点,否则插入不了HeroNode temp = head;boolean flag = false;//flag,标识添加的编号是否存在,默认为falsewhile (true) {if (temp.next == null) {//说明temp已经在链表的最后break;}if (temp.next.no > heroNode.no) {//位置找到,就在temp的后面插入break;} else if (temp.next.no == heroNode.no) {//说明希望添加的heroNode的编号已经存在flag = true;break;}temp = temp.next;//后移,遍历当前链表}//判断flag的值if (flag) {System.out.printf("准备插入的英雄的编号 %d 已经存在了,不能加入\n", heroNode.no);} else {//插入到链表中,temp的后面heroNode.next = temp.next;temp.next = heroNode;}}//修改节点的信息,根据no编号来修改,即no编号不能改//说明//1.根据 newHeroNode 的 no 来修改即可public void update(HeroNode newHeroNode) {//判断是否为空if (head.next == null) {System.out.println("链表为空");return;}//找到需要修改的节点,根据no编号//定义一个辅助变量HeroNode 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.head不能动,因此我们需要一个temp辅助节点找到待删除节点的前一个节点//2.说明我们在比较时,是temp.next.no 和 需要删除的节点的 no比较public void del(int no) {HeroNode temp = head;boolean flag = false;//标识是否找到待删除节点while (true) {if (temp.next == null) {break;//已经到了链表的最后}if (temp.next.no == no) {//找到的待删除节点的前一个节点 tempflag = true;break;}temp = temp.next;//temp后移,遍历}//判断flagif (flag) {//找到,可以删除temp.next = temp.next.next;} else {System.out.printf("要删除的 %d 的节点不存在\n", no);}}//显示链表【遍历】public void list() {//判断链表是否为空if (head.next == null) {System.out.println("链表为空");return;}//因为头节点,不能动,因此我们需要一个辅助遍历来遍历HeroNode temp = head.next;while (true) {//判断是否到链表最后if (temp == null) {break;}//输出节点的信息System.out.println(temp);//将temp后移,一定小心temp = temp.next;}}
}//定义HeroNode,每个HeroNode 对象就是一个节点
class HeroNode {public int no;public String name;public String nickName;public HeroNode next;//指向下一个节点//构造器public HeroNode(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 + '\'' +'}';}
}
HeroNode{no=1, name='宋江', nickName='及时雨'}
HeroNode{no=2, name='卢俊义', nickName='玉麒麟'}
HeroNode{no=3, name='吴用', nickName='智多星'}
HeroNode{no=4, name='林冲', nickName='豹子头'}删除后的节点:
HeroNode{no=2, name='卢俊义', nickName='玉麒麟'}
HeroNode{no=3, name='吴用', nickName='智多星'}
HeroNode{no=4, name='林冲', nickName='豹子头'}

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

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

相关文章

使用git rebase 之后的如何恢复到原始状态

我们常常喜欢使用git rebase去切换分支提交代码,操作流程就是: 先切换分支:比如当前是master 我们修改了一堆代码产生一个commit id :5555555567777 那么我们常常比较懒就直接切换了:git checkout dev 然后呢?使用命令git rebase 5555555567777,想把这笔修改提交到d…

SpringBoot-lombok

为什么要使用lombok? Lombok是一个通过注解以达到减少代码的Java库,如通过注解的方式减少getter,setter方法,构造方法等。通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高…

[uni-app] uview封装Popup组件,处理props及v-model的传值问题

文章目录 需求及效果遇到的问题解决的办法偷懒的写法 需求及效果 uView(1.x版本)中, 有Pop弹出层的组件, 现在有个需求是,进行简单封装,有些通用的设置不想每次都写(比如 :mask-custom-style"{background: rgba(0, 0, 0, 0.7)}"这种) 然后内部内容交给插槽去自己随…

vue实例挂载过程

以下仅为个人见解。 1.大致流程: new Vue()时会调用initMixin(Vue)将_init挂载到vue原型上;在_init()中调用$mount()方法($mount()方法也是挂载到vue原型上的)编译template模版,并生成render()函数;挂载到vm上后,会…

【【Verilog典型电路设计之FIFO设计】】

典型电路设计之FIFO设计 FIFO (First In First Out)是一种先进先出的数据缓存器,通常用于接口电路的数据缓存。与普通存储器的区别是没有外部读写地址线,可以使用两个时钟分别进行写和读操作。FIFO只能顺序写入数据和顺序读出数据&#xff0…

【报错】git push --set-upstream origin XXXX重名

您在尝试将分支推送到远程仓库时遇到了错误。错误信息表明,由于已经存在名为 refs/heads/xingfan/demo 的文件夹,Git 无法创建分支 refs/heads/xingfan。 要解决此问题,您可以尝试重命名本地分支,然后将其推送到远程仓库。以下是…

大模型基础02:GPT家族与提示学习

大模型基础:GPT 家族与提示学习 从 GPT-1 到 GPT-3.5 GPT(Generative Pre-trained Transformer)是 Google 于2018年提出的一种基于 Transformer 的预训练语言模型。它标志着自然语言处理领域从 RNN 时代进入 Transformer 时代。GPT 的发展历史和技术特点如下: GP…

无脑入门pytorch系列(三)—— nn.Linear

本系列教程适用于没有任何pytorch的同学(简单的python语法还是要的),从代码的表层出发挖掘代码的深层含义,理解具体的意思和内涵。pytorch的很多函数看着非常简单,但是其中包含了很多内容,不了解其中的意思…

Linux Kernel的local_irq_enable()和local_irq_disable()函数

代码如下图所示,最终操作的是msr daifset, #3 和 msr daifclr, #3 寄存器。 (include/linux/irqflags.h) #define local_irq_enable() do { raw_local_irq_enable(); } while (0) #define local_irq_disable() do { raw_local_irq_disable(); } while (0)#define ra…

【AIGC】 国内版聊天GPT

国内版聊天GPT 引言一、国内平台二、简单体验2.1 提问2.2 角色扮演2.3 总结画图 引言 ChatGPT是OpenAI发开的聊天程序,功能强大,可快速获取信息,节省用户时间和精力,提供个性化的服务。目前国产ChatGPT,比如文心一言&a…

C语言:选择+编程(每日一练)

目录 选择题: 题一: 题二: 题三: 题四: 题五: 编程题: 题一:尼科彻斯定理 示例1 题二:等差数列 示例2 本人实力有限可能对一些地方解释和理解的不够清晰&…

【计算机视觉|生成对抗】逐步增长的生成对抗网络(GAN)以提升质量、稳定性和变化

本系列博文为深度学习/计算机视觉论文笔记,转载请注明出处 标题:Progressive Growing of GANs for Improved Quality, Stability, and Variation 链接:[1710.10196] Progressive Growing of GANs for Improved Quality, Stability, and Vari…

mac垃圾清理软件有哪些

随着使用时间的增加,mac系统会产生一些垃圾文件,影响系统的性能和稳定性。为了保持mac系统的高效,用户需要定期使用mac垃圾清理软件来清理系统缓存、日志、语言包等无用文件。CleanMyMac是一款功能强大的mac垃圾清理软件,它可以帮…

Python学习笔记_进阶篇(二)_django知识(一)

本章简介: Django 简介Django 基本配置Django urlDjango viewDjango 模板语言Django Form Django 简介 Django是一个开放源代码的Web应用框架,由Python写成。采用了MVC的软件设计模式,即模型M,视图V和控制器C。它最初是被开发来…

【Linux操作系统】详解Linux系统编程中的管道进程通信

在Linux系统编程中,管道是一种常用的进程间通信方式。它可以实现父子进程之间或者兄弟进程之间的数据传输。本文将介绍如何使用管道在Linux系统中进行进程通信,并给出相应的代码示例。 文章目录 1. 管道的概念2. 管道的创建和使用2.1 原型2.2 示例 3. 父…

keepalived集群

keepalived概述 keepalived软件就是通过vrrp协议来实现高可用功能。 VRRP通信原理 VRRP就是虚拟路由冗余协议,它的出现就是为了解决静态路由的单点故障。 VRRP是通过一种竞选一种协议机制来将路由交个某台VRRP路由器。 VRRP 用IP多播的方式(多播地…

HTTP与HTTPS的区别

面试常见问题,HTTPS优化总结易记版: 1、HSTS重定向技术:将http自动转换为https,减少301重定向 2、TLS握手优化:在TLS握手完成前客户端就提前向服务器发送数据 3、会话标识符:服务器记录下与某客户端的会…

学习笔记|按键原理|消抖|按键点灯的4种模式|STC32G单片机视频开发教程(冲哥)|第七集:按键点灯

文章目录 第六集(下)课后练习解答:SOS求救灯光编写求救信号原理冲哥代码及解析分模块设计:math.h:math.c:while主程序部分 按键点灯(下)1.按键的原理Tips:按键消抖 2.按键的代码实现…

创建一个简单的HTML Viewer应用程序

使用wxPython和内嵌浏览器来创建一个简单的HTML Viewer应用程序。 在本篇文章中,我们将使用Python和wxPython模块来创建一个简单的HTML Viewer应用程序。这个应用程序可以让用户输入HTML内容,并在内嵌浏览器中显示该内容的效果。 准备工作 在开始之前…

PCL 三维点云边界提取(C++详细过程版)

边界提取 一、概述二、代码实现三、结果展示本文由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述 点云边界提取在PCL里有现成的调用函数,具体算法原理和实现代码见:PCL 点云边界提取。为充分了解pcl::BoundaryEsti…