链表

链表(Linked List)#

链表是一种链式存储的线性表,所有元素的内存地址不一定是连续的

1599390369768

链表的设计#

1599390498403

链表是有序的列表,但是它在内存中是这样存储

image-20210315200413826

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

单链表(带头结点)逻辑结构示意图

image-20210315200746348

代码实现#

单链表创建示意图(添加)

image-20210315203926661

Copy
package com.sun.atguigu.linkedlist; /** * @author 孙冲 * 单向链表 * @date 2021-3-15 */ public class SingleLinkedListDemo { public static void main(String[] args) { HeroNode hear1 = new HeroNode(1,"宋江","及时雨"); HeroNode hear2 = new HeroNode(2,"卢俊义","玉麒麟"); HeroNode hear3 = new HeroNode(3,"吴用","智多星"); HeroNode hear4 = new HeroNode(4,"林冲","豹子头"); SingleLinkedList singleLinkedList = new SingleLinkedList(); //如果不按顺序添加 singleLinkedList.add(hear1); singleLinkedList.add(hear2); singleLinkedList.add(hear3); singleLinkedList.add(hear4); singleLinkedList.list(); } } //定义SingleLinkedList 管理数据 class SingleLinkedList { //先初始化一个头节点,头节点不要动,不存放具体数据 private HeroNode head = new HeroNode(0,"",""); //添加节点到单向链表(不考虑编号顺序) //找到当前链表的最后节点 //将最后这个节点的next指向新的节点 public void add(HeroNode headNode) { //因为head节点不能动,我们需要一个辅助遍历 temp HeroNode temp = head; //遍历链表,找到最后 while (true) { if (temp.next == null) { break; } //如果没有找到最后,将temp后移。若不后移将造成死循环 temp = temp.next; } //当退出while循环的时候,temp就指向了链表的最后 //将最后这个节点的next指向新的节点 temp.next = headNode; } //显示链表数据 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; } } } 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; } @Override public String toString() { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", nickname='" + nickname + '\'' + '}'; } }

image-20210316200445129

Copy
package com.sun.atguigu.linkedlist; /** * @author 孙冲 * 单向链表 * @date 2021-3-15 */ public class SingleLinkedListDemo { public static void main(String[] args) { HeroNode hear1 = new HeroNode(1,"宋江","及时雨"); HeroNode hear2 = new HeroNode(2,"卢俊义","玉麒麟"); HeroNode hear3 = new HeroNode(3,"吴用","智多星"); HeroNode hear4 = new HeroNode(4,"林冲","豹子头"); SingleLinkedList singleLinkedList = new SingleLinkedList(); //如果不按顺序添加 /* singleLinkedList.add(hear1); singleLinkedList.add(hear2); singleLinkedList.add(hear3); singleLinkedList.add(hear4); singleLinkedList.list();*/ //按照编号的顺序加入 singleLinkedList.addByOrder(hear1); singleLinkedList.addByOrder(hear2); singleLinkedList.addByOrder(hear4); singleLinkedList.addByOrder(hear3); singleLinkedList.list(); } } //定义SingleLinkedList 管理数据 class SingleLinkedList { //先初始化一个头节点,头节点不要动,不存放具体数据 private HeroNode head = new HeroNode(0,"",""); //添加节点到单向链表(不考虑编号顺序) //找到当前链表的最后节点 //将最后这个节点的next指向新的节点 public void add(HeroNode headNode) { //因为head节点不能动,我们需要一个辅助遍历 temp HeroNode temp = head; //遍历链表,找到最后 while (true) { if (temp.next == null) { break; } //如果没有找到最后,将temp后移。若不后移将造成死循环 temp = temp.next; } //当退出while循环的时候,temp就指向了链表的最后 //将最后这个节点的next指向新的节点 temp.next = headNode; } //第二种方式在添加英雄时,根据排名将英雄插入到指定位置 //(如果有这个排名,则添加失败,并给出提示) public void addByOrder(HeroNode headNode) { //因为头节点不能动,通过一个辅助指针(变量)来找到添加的位置 //因为单链表,找的temp是位于添加位置的前一个节点,否则插入不了 HeroNode temp = head; //标志添加的编号是否存在,默认为false boolean flag = false; while (true) { //判断temp是否已经在链表的最后 if (temp.next == null) { break; } //位置找到,就在temp的后面插入 if (temp.next.no > headNode.no) { break; }else if (temp.next.no == headNode.no) { //判断添加的heroNode编号是否存在 //说明编号存在 flag = true; break; } //向后移动,遍历当前链表 temp = temp.next; } //判断flag的值 if (flag) { //编号存在 System.out.printf("准备插入的英雄编号%d已经存在,不能加入",headNode.no); }else { //插入到链表中,temp的后面 headNode.next = temp.next; temp.next = headNode; } } //显示链表数据 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; } } } 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; } @Override public String toString() { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", nickname='" + nickname + '\'' + '}'; } }

根据编号修改节点的信息

Copy
package com.sun.atguigu.linkedlist; /** * @author 孙冲 * 单向链表 * @date 2021-3-15 */ public class SingleLinkedListDemo { public static void main(String[] args) { HeroNode hear1 = new HeroNode(1,"宋江","及时雨"); HeroNode hear2 = new HeroNode(2,"卢俊义","玉麒麟"); HeroNode hear3 = new HeroNode(3,"吴用","智多星"); HeroNode hear4 = new HeroNode(4,"林冲","豹子头"); SingleLinkedList singleLinkedList = new SingleLinkedList(); //如果不按顺序添加 /* singleLinkedList.add(hear1); singleLinkedList.add(hear2); singleLinkedList.add(hear3); singleLinkedList.add(hear4); singleLinkedList.list();*/ //按照编号的顺序加入 singleLinkedList.addByOrder(hear1); singleLinkedList.addByOrder(hear2); singleLinkedList.addByOrder(hear4); singleLinkedList.addByOrder(hear3); singleLinkedList.list(); //修改 HeroNode newHeroNode = new HeroNode(2, "卢俊义1111", "玉麒麟2222"); singleLinkedList.update(newHeroNode); System.out.println("修改后的数据链表"); singleLinkedList.list(); } } //定义SingleLinkedList 管理数据 class SingleLinkedList { //先初始化一个头节点,头节点不要动,不存放具体数据 private HeroNode head = new HeroNode(0,"",""); //添加节点到单向链表(不考虑编号顺序) //找到当前链表的最后节点 //将最后这个节点的next指向新的节点 public void add(HeroNode headNode) { //因为head节点不能动,我们需要一个辅助遍历 temp HeroNode temp = head; //遍历链表,找到最后 while (true) { if (temp.next == null) { break; } //如果没有找到最后,将temp后移。若不后移将造成死循环 temp = temp.next; } //当退出while循环的时候,temp就指向了链表的最后 //将最后这个节点的next指向新的节点 temp.next = headNode; } //第二种方式在添加英雄时,根据排名将英雄插入到指定位置 //(如果有这个排名,则添加失败,并给出提示) public void addByOrder(HeroNode headNode) { //因为头节点不能动,通过一个辅助指针(变量)来找到添加的位置 //因为单链表,找的temp是位于添加位置的前一个节点,否则插入不了 HeroNode temp = head; //标志添加的编号是否存在,默认为false boolean flag = false; while (true) { //判断temp是否已经在链表的最后 if (temp.next == null) { break; } //位置找到,就在temp的后面插入 if (temp.next.no > headNode.no) { break; }else if (temp.next.no == headNode.no) { //判断添加的heroNode编号是否存在 //说明编号存在 flag = true; break; } //向后移动,遍历当前链表 temp = temp.next; } //判断flag的值 if (flag) { //编号存在 System.out.printf("准备插入的英雄编号%d已经存在,不能加入",headNode.no); }else { //插入到链表中,temp的后面 headNode.next = temp.next; temp.next = headNode; } } //修改节点的信息,根据no编号来修改,no编号不能改 public void update(HeroNode newHeroNode) { //判断是否为空 if (head.next == null) { System.out.println("链表数据为空"); } //找到需要修改的节点,根据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; } 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; } } } 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; } @Override public String toString() { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", nickname='" + nickname + '\'' + '}'; } }

节点删除

image-20210317203439849

Copy
package com.sun.atguigu.linkedlist; /** * @author 孙冲 * 单向链表 * @date 2021-3-15 */ public class SingleLinkedListDemo { public static void main(String[] args) { HeroNode hear1 = new HeroNode(1,"宋江","及时雨"); HeroNode hear2 = new HeroNode(2,"卢俊义","玉麒麟"); HeroNode hear3 = new HeroNode(3,"吴用","智多星"); HeroNode hear4 = new HeroNode(4,"林冲","豹子头"); SingleLinkedList singleLinkedList = new SingleLinkedList(); //如果不按顺序添加 /* singleLinkedList.add(hear1); singleLinkedList.add(hear2); singleLinkedList.add(hear3); singleLinkedList.add(hear4); singleLinkedList.list();*/ //按照编号的顺序加入 singleLinkedList.addByOrder(hear1); singleLinkedList.addByOrder(hear2); singleLinkedList.addByOrder(hear4); singleLinkedList.addByOrder(hear3); singleLinkedList.list(); //修改 HeroNode newHeroNode = new HeroNode(2, "卢俊义1111", "玉麒麟2222"); singleLinkedList.update(newHeroNode); System.out.println("修改后的数据链表"); singleLinkedList.list(); //删除节点 singleLinkedList.del(1); singleLinkedList.del(5); System.out.println("删除后的链表数据"); singleLinkedList.list(); } } //定义SingleLinkedList 管理数据 class SingleLinkedList { //先初始化一个头节点,头节点不要动,不存放具体数据 private HeroNode head = new HeroNode(0,"",""); //添加节点到单向链表(不考虑编号顺序) //找到当前链表的最后节点 //将最后这个节点的next指向新的节点 public void add(HeroNode headNode) { //因为head节点不能动,我们需要一个辅助遍历 temp HeroNode temp = head; //遍历链表,找到最后 while (true) { if (temp.next == null) { break; } //如果没有找到最后,将temp后移。若不后移将造成死循环 temp = temp.next; } //当退出while循环的时候,temp就指向了链表的最后 //将最后这个节点的next指向新的节点 temp.next = headNode; } //第二种方式在添加英雄时,根据排名将英雄插入到指定位置 //(如果有这个排名,则添加失败,并给出提示) public void addByOrder(HeroNode headNode) { //因为头节点不能动,通过一个辅助指针(变量)来找到添加的位置 //因为单链表,找的temp是位于添加位置的前一个节点,否则插入不了 HeroNode temp = head; //标志添加的编号是否存在,默认为false boolean flag = false; while (true) { //判断temp是否已经在链表的最后 if (temp.next == null) { break; } //位置找到,就在temp的后面插入 if (temp.next.no > headNode.no) { break; }else if (temp.next.no == headNode.no) { //判断添加的heroNode编号是否存在 //说明编号存在 flag = true; break; } //向后移动,遍历当前链表 temp = temp.next; } //判断flag的值 if (flag) { //编号存在 System.out.printf("准备插入的英雄编号%d已经存在,不能加入",headNode.no); }else { //插入到链表中,temp的后面 headNode.next = temp.next; temp.next = headNode; } } //修改节点的信息,根据no编号来修改,no编号不能改 public void update(HeroNode newHeroNode) { //判断是否为空 if (head.next == null) { System.out.println("链表数据为空"); } //找到需要修改的节点,根据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; } if (flag) { temp.name = newHeroNode.name; temp.nickname = newHeroNode.nickname; }else { System.out.printf("没有找到编号%d的节点,不能修改\n",newHeroNode.no); } } //删除节点 //head节点不能动,需要一个temp辅助节点找到待删除节点的前一个节点 //在比较时,是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) { flag = true; break; } //temp后移 temp = temp.next; } if (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; } } } 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; } @Override public String toString() { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", nickname='" + nickname + '\'' + '}'; } }
posted @   striver-sc  阅读(81)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示
CONTENTS