4、链表
基本介绍
概念
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
特点
-
链表是以节点的方式来存储,是链式存储。
-
每个节点包含 data 域, next 域:指向下一个节点。
-
如图:发现链表的各个节点不一定是连续存储。
-
链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定。
单链表
单链表创建和遍历的分析实现
添加(创建):
- 先创建一个head头节点,作用就是表示单链表的头。
- 之后每添加一个结点,就直接加入到链表的最后 。 no :编号 name: 名字 昵称:nickName
//java版最新代码: package com.atguigu; public class SingleLinkedListDemo { public static void main(String[] args) { // TODO Auto-generated method stub // 测试单向链表的添加和遍历 HeroNode hero1 = new HeroNode(1, "宋江", "及时雨"); HeroNode hero2 = new HeroNode(3, "宋江3", "及时雨3"); HeroNode hero3 = new HeroNode(4, "宋江4", "及时雨4"); HeroNode hero4 = new HeroNode(2, "宋江2", "及时雨2"); // 创建一个单向链表 SingleLinkedList singleLinkedList = new SingleLinkedList(); // singleLinkedList.add(hero1); // singleLinkedList.add(hero2); // singleLinkedList.add(hero3); // singleLinkedList.add(hero4); singleLinkedList.add2(hero1); singleLinkedList.add2(hero2); singleLinkedList.add2(hero3); singleLinkedList.add2(hero4); singleLinkedList.list(); HeroNode hero5 = new HeroNode(3, "吴用", "智多星"); singleLinkedList.update(hero5); System.out.println("=========================="); singleLinkedList.list(); System.out.println("@@@@@@@@@@测试删除@@@@@@@@@@@"); singleLinkedList.del(4); singleLinkedList.del(2); singleLinkedList.del(1); singleLinkedList.list(); } } // 定义我们的单向链表管理Hero class SingleLinkedList { // 先初始化一个头结点, 头结点一般不会动 private HeroNode head = new HeroNode(0, "", ""); // 删除节点 // 1. 思路 // 删除的思路 // 1). head 不能动 // 2). 使用temp变量, 我们要删除的应该是temp 的下一个结点., 即,我们在比较时,始终比较的是 temp.next 的节点值 // 2. 代码 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.next; // temp后移 } if (flag) { // 可以删除 temp.next = temp.next.next; } else { System.out.printf("要删除的no=%d 不存在\n", no); } } // 修改节点的值, 根据no编号为前提修改, 即no不能改 // 课后思考题: 如果将这个节点替换,如何实现 public void update(HeroNode newHeroNode) { if (head.next == null) { System.out.println("链表为空"); return; } // 先找到节点 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 add(HeroNode heroNode) { // 因为头结点不能动, 因此我们需要哟有一个临时结点,作为辅助 HeroNode temp = head; // 找到链表的最后 while (true) { if (temp.next == null) { // 说明temp已经是链表最后 break; } // 如果没有到最后 temp = temp.next; } // 当退出while循环后,temp就是链表的最后 temp.next = heroNode; } // 第二种方式在添加英雄时,根据排名将英雄插入到指定位置 // 如果有这个排名,则添加失败,并给出提示 // 编号从小到大排序 // 思路 public void add2(HeroNode heroNode) { // 因为头结点不能动, 因此我们需要哟有一个临时结点,作为辅助 // 注意,我们在找这个添加位置时,是将这个节点加入到temp的后面 // 因此,在比较时,是将当前的heroNode 和 temp.next 比较 HeroNode temp = head; boolean flag = false; // flag 是用于判断是否该英雄的编号已经存在, 默认为false while (true) { if (temp.next == null) { // 说明temp已经是链表最后 break; } if (temp.next.no > heroNode.no) { // 位置找到,当前这个节点,应当加入到temp后 break; } else if (temp.next.no == heroNode.no) { // 已经有这个节点 flag = true; break; } temp = temp.next; // 注意 } if (flag) { // 不可以加入 System.out.printf("待插入的英雄编号 %d 已经有了,不能加入\n", heroNode.no); } else { // 加入,注意顺序 heroNode.next = temp.next; temp.next = heroNode; } } // 遍历单向链表 public void list() { // 判断当前链表是否为空 if (head.next == null) { System.out.println("链表为空!!"); return; } // 因为头结点不能动, 因此我们需要哟有一个临时结点,作为辅助 // 因为head 结点数据,我们不关心,因此这里 temp=head.next HeroNode temp = head.next; while (true) { // 判断是否到最后 if (temp == null) { break; } System.out.printf("结点信息 no=%d name=%s nickname=%s\n", temp.no, temp.name, temp.nickname); temp = temp.next; } } } // 先创建HeroNode class HeroNode { public int no; public String name; public String nickname; public HeroNode next; // next 默认为null public HeroNode(int hNo, String hName, String hNickname) { no = hNo; name = hName; nickname = hNickname; } } //结束============================================
实现在单链表指定位置插入元素,并实现结点删除和修改
在数据1和数据4之间添加数据2:先让数据2的next域指向temp.next,也就是指向数据4,然后再让数据1的next域指向数据2。
修改节点思想:
删除节点思想:
//最新代码 package com.atguigu.temp.linkedlist import util.control.Breaks._ object SingleLinkedListTest { def main(args: Array[String]): Unit = { //测试一下 //创建HeroNode val hero1 = new HeroNode(1,"宋江","及时雨") val hero2 = new HeroNode(2,"宋江2","及时雨2") val hero3 = new HeroNode(4,"宋江4","及时雨4") val hero6 = new HeroNode(3,"宋江3","及时雨3") //创建 val singleLinkedList = new SingleLinkedList singleLinkedList.add2(hero1) singleLinkedList.add2(hero2) singleLinkedList.add2(hero3) singleLinkedList.add2(hero6) singleLinkedList.list() //删除 println("~~~~~~~~~~~~~~~~~~~~~~~~~~") //singleLinkedList.del(1) //singleLinkedList.del(2) //singleLinkedList.del(4) //singleLinkedList.list() //测试修改 // println("===========修改===============") // val hero4 = new HeroNode(2,"吴用","智多星") // singleLinkedList.update(hero4) // //修改后 // singleLinkedList.list() } } class SingleLinkedList { val head = new HeroNode(0, "", "") //添加方法, 方式1: def add(heroNode: HeroNode): Unit = { //head 是头结点,不用改变 var temp = head breakable { while (true) { if (temp.next == null) { break() } temp = temp.next } } temp.next = heroNode } //安装编号的大小来插入 def add2(heroNode: HeroNode): Unit = { //head 是头结点,不用改变 var temp = head var flag = false // 表示是否已经存在 breakable { while (true) { if (temp.next == null) { break() // 最后了 } if (temp.next.no > heroNode.no) { //找到了 break() //就应该插入到temp节点后面 } if (temp.next.no == heroNode.no) { //已经有了 flag = true break() } temp = temp.next } } if (!flag) { // 没有该节点, 可以添加 heroNode.next = temp.next temp.next = heroNode } else { printf("你要添加的no=%d 的节点已经存在!\n", heroNode.no) } } //显示单链表 def list(): Unit = { var temp = head.next breakable { while (true) { if (temp == null) { break() } printf("当前节点信息 no=%d name=%s nickname=%s\n", temp.no, temp.name, temp.nickName) temp = temp.next } } } //删除 //思路: def del(no:Int): Unit = { var temp = head //要删除的是temp.next 节点,而不是temp节点,需要考虑单链表 var flag = false breakable { while (true) { if (temp.next == null) { break() } if (temp.next.no == no) { //找到了 flag = true break() } temp = temp.next } } if (flag) { //找到 temp.next = temp.next.next }else{ printf("你删除的no=%d 的节点不存在,无法删除\n", no) } } //修改, 给你一个新的node ,修改对应的值 def update(newHeroNode:HeroNode): Unit = { var temp = head.next var flag = false //先找到这个节点 breakable { while (true) { if (temp == null) { break() } if (temp.no == newHeroNode.no) { //找到了 flag = true break() } temp = temp.next } } if (flag) { //找到 temp.nickName = newHeroNode.nickName temp.name = newHeroNode.name }else{ printf("你修改的no=%d 的节点不存在,无法修改\n", newHeroNode.no) } } } class HeroNode(hNo: Int, hName: String, hNickName: String) { var no: Int = hNo var name: String = hName var nickName: String = hNickName var next: HeroNode = null }