第 4 章 链表(1)

news/2024/12/29 18:42:14/

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.ppmy.cn/news/1042330.html

相关文章

Unity制作一个简单的登入注册页面

1.创建Canvas组件 首先我们创建一个Canvas画布,我们再在Canvas画布底下创建一个空物体,取名为Resgister。把空物体的锚点设置为全屏撑开。 2.我们在Resgister空物体底下创建一个Image组件,改名为bg。我们也把它 的锚点设置为全屏撑开状态。接…

rust踩雷笔记3——生命周期的理解

目录 概念和基本使用一个例子彻底理解最基本的内容 一个例子理解函数签名为什么要有生命周期标注⭐️能不能对编译器蒙混过关? 生命周期是rust中最难的概念——鲁迅 这一块内容即便是看rust圣经,第一遍也有点懵。今天早上二刷突然有了更直观的认识&…

springboot数据库密码加密的配置方法_Java

前言 由于系统安全的考虑&#xff0c;配置文件中不能出现明文密码的问题&#xff0c;本文就给大家详细介绍下springboot配置数据库密码加密的方法&#xff0c;下面话不多说了&#xff0c;来一起看看详细的介绍吧 1.导入依赖 <!--数据库密码加密--> <dependency>&…

【算法心得】正确估计dfs时间复杂度;剪枝优化不怕重构

https://leetcode.cn/problems/verbal-arithmetic-puzzle/ 这题看到题&#xff0c;“表达式中使用的不同字符数最大为 10”&#xff0c;就觉得dfs就完事了&#xff0c;最多不过10!&#xff0c;10!才1e6&#xff0c;1e7这样。如果字符再少点&#xff0c;6! 7! 8!的&#xff0c;…

Java之抽象类

Java之抽象类 抽象类概念抽象类如何使用抽象类的特性 作者简介&#xff1a; zoro-1&#xff0c;目前大一&#xff0c;正在学习Java&#xff0c;数据结构等 作者主页&#xff1a;zoro-1的主页 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f49…

Pandas+Pyecharts | 成都大运会奖牌数据分析可视化

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 数据信息2.3 数据处理 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 每日奖牌数量分布3.2 奖牌榜单TOP20金银铜牌分布3.3 各比赛项目金牌…

微服务参数透传实现

说明&#xff1a;在微服务架构中&#xff0c;用户身份经网关验证后&#xff0c;我们可以将用户信息&#xff0c;如ID加入到请求头上。后面的微服务中&#xff0c;可以设置一个拦截器&#xff0c;拦截请求&#xff0c;获取请求头上的用户ID&#xff0c;加入到ThreadLocal中。 最…

NLP | 论文摘要文本分类

基于论文摘要的文本分类与关键词抽取挑战赛​​​​​​2023 iFLYTEK A.I.开发者大赛-讯飞开放平台 环境需求&#xff1a;Anaconda-JupyterNotebook&#xff0c;或者百度AIStudio 赛题解析&#xff1a; 【文本二分类任务】根据论文摘要等信息理解&#xff0c;将论文划分为0-1两…