2.双向链表的应用实例
使用带head头的双向链表实现-水浒英雄排行榜管理。
单向链表的缺点分析:
1)单向链表,查找的方向只能是一个方向,而双向链表可以向前或向后查找。
2)单向链表不能自我删除,需要靠辅助结点,而双向链表,则可以自我删除,所以前面我们单链表删除结点时,总是找到temp的下一个结点来删除的。
将前面的单向链表改成双向链表。
代码实现
package chapter18.linkedList
import scala.util.control.Breaks.{break, breakable}
object DoubleLinkedListDemo {
def main(args: Array[String]): Unit = {
//测试链表的添加和遍历
val hero1 = new HeroNode2(1, "宋江1", "及时雨1")
val hero2 = new HeroNode2(3, "宋江3", "及时雨3")
val hero3 = new HeroNode2(4, "宋江4", "及时雨4")
val hero4 = new HeroNode2(2, "宋江2", "及时雨2")
val hero6 = new HeroNode2(6, "孙二娘", "母老虎")
//创建一个单向链表
val doubleLinkedList = new DoubleLinkedList
doubleLinkedList.add(hero1) //无序加入
doubleLinkedList.add(hero2) //无序加入
doubleLinkedList.add(hero3) //无序加入
// doubleLinkedList.add(hero4) //
doubleLinkedList.add2(hero4) //有序加入
doubleLinkedList.add2(hero6) //有序加入
doubleLinkedList.list()
println("--------------------修改----------------------")
val hero5 = new HeroNode2(3, "卢俊义", "玉麒麟")
doubleLinkedList.update(hero5)
doubleLinkedList.list()
println("---------------------删除---------------------")
doubleLinkedList.del(2)
doubleLinkedList.del(3)
doubleLinkedList.del(4)
doubleLinkedList.list()
println("---------------------再次加入-----------------")
doubleLinkedList.add(hero2) // 无序加入
doubleLinkedList.list()
}
}
/**
* 创建双向链表
*/
class DoubleLinkedList {
//先初始化一个头结点,头结点一般不会动
val head = new HeroNode2(0, "", "")
//方法创建模式:添加-遍历-修改-删除
/**
* 添加
* 方法1:直接添加到链表的尾部
*
* @param heroNode hero节点
*/
def add(heroNode: HeroNode2): Unit = {
//因为头结点不动,因此我们需要有一个零时节点,作为辅助功能。
var temp = head
//找到链表的最后
breakable {
while (true) {
if (temp.next == null) {
//说明temp已经是链表的最后
break()
}
//如果没有到最后
temp = temp.next
}
}
//当退出while循环后,temp就是链表的最后
temp.next = heroNode
heroNode.pre = temp
}
/**
* 添加
* 添加方法2:根据排名将英雄插入到指定位置,如果有这个排名,则添加失败,并给出提示
*
* @param heroNode hero节点
*/
def add2(heroNode: HeroNode2): Unit = {
//因为头结点不动,因此我们需要有一个零时节点,作为辅助功能。
var temp = head
var flag = 0 //标志temp的状态,1:temp后面无节点,2:temp后面有节点。
//找到链表的最后
breakable {
while (true) {
if (temp.next == null) {
//说明temp已经是链表的最后
flag = 1
break()
}
if (temp.no == heroNode.no) {
println(s"编号为${heroNode.no}的英雄已存在,不能继续添加")
return
}
if (temp.next.no > heroNode.no) { //下一个节点之前进行添加
flag = 2
break()
}
//如果没有到最后
temp = temp.next
}
}
if (flag == 1) {
//temp是最后一个节点
temp.next = heroNode
heroNode.pre = temp
} else if (flag == 2) {
//temp后面还有节点
heroNode.pre = temp
heroNode.next = temp.next
temp.next.pre = heroNode
temp.next = heroNode
}
}
/**
* 修改节点的值,依据为编号 no
*
* @param newHeroNode 修改后的节点
*/
def update(newHeroNode: HeroNode2): Unit = {
if (head.next == null) {
println("链表为空")
return
}
//先找到这个节点
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.name = newHeroNode.name
temp.nickname = newHeroNode.nickname
} else {
printf("未找到编号为%d的节点,不能修改。\n", newHeroNode.no)
}
}
/**
* 遍历链表
*/
def list(): Unit = {
//判断当前链表是否为空
if (head.next == null) {
println("当前链表为空")
return
}
//因为头结点不能动,因此我们需要有一个临时节点,作为辅助
//因为头结点的数据,我们不关心,因此这里temp = head.next
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
}
}
}
/**
* 删除:自我删除
*
* @param no 要删除hero的编号
*/
def del(no: Int): Unit = {
//判断当前列表是否为空
if (head.next == null) {
println("链表空")
return
}
var temp = head.next
var flag = false //标志变量,用于确定是否有要删除的这个结点
breakable {
while (true) {
if (temp == null) {
break()
}
if (temp.no == no) {
flag = true
break()
}
temp = temp.next
}
}
if (flag) { //可以删除
//temp.next = temp.next.next
temp.pre.next = temp.next
if (temp.next != null) {
temp.next.pre = temp.pre
}
//设置当前节点的前后节点均为null
temp.pre = null
temp.next = null
} else {
printf("标号为%d的结点不存在\n", no)
}
}
}
/**
* 创建双向节点 HeroNode2
*
* @param hNo 编号
* @param hName 姓名
* @param hNickname 外号
*/
class HeroNode2(hNo: Int, hName: String, hNickname: String) {
var no: Int = hNo
var name: String = hName
var nickname: String = hNickname
var pre: HeroNode2 = null // pre 默认为null
var next: HeroNode2 = null //next 默认为null
}