链表(LinkedList)-双向链表

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
}

运行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值