103、scala-鏈表之單向雙向

一、什麼是鏈表

鏈表是有序的列表,但是它在內存中是存儲如下:

在這裏插入圖片描述

總結

  1. 鏈表是一個有序列表
  2. 鏈表的數據,在內存空間不一定是連續分佈的
  3. 鏈表又分單向、雙向或者循環

區別:
1、單向鏈表
2、雙向鏈表
3、循環鏈表(單向循環,雙向循環)

如下圖
在這裏插入圖片描述
在這裏插入圖片描述

使用場景及優缺點:
單向鏈表:
1、單向鏈表需要實現隊列,建設頭結點是尾部,入隊速度快,但是每次出隊需要遍歷到最後一個節點
2、實現棧則比較完美
3、鏈表移除數據需要臨時節點來記錄待刪除節點的前一個節點

雙向鏈表:
1、頭尾節點都有並且是雙向,則實現隊列不用遍歷數據,頭尾一出一進,完美配合
2、刪除數據時不需要臨時節點,只需將刪除節點的前一個節點的向後指向刪除節點的後一個,刪除節點的後一個節點指向前一個節點即可

循環鏈表:解決特殊的算法問題,後續案例介紹

二、代碼實操

1、單向鏈表代碼
object DanxLink {

  def main(args: Array[String]): Unit = {
    val link = new DanxLink()
    //    (0 to 10).foreach(link.addFirstNode(_))
    (0 to 10).foreach(link.addLastNode(_))
    link.showData()
    println()
    println(link.size())
    println(link.get(3))
    println(link.remove(3))
    println(link.get(3))
    println(link.size())
    link.showData()

  }
}

/**
  * 單向鏈表只能從前頭結點向後查找
  * head-->1-->2-->3-->4-->null
  */
class DanxLink {
  //頭結點
  val head = new Node
  //長度
  private var length = 0

  //添加在首位
  def addFirstNode(value: Int): Unit = {
    add(value, 0, 0, head)
  }

  //末尾添加
  def addLastNode(value: Int): Unit = {
    add(value, length, 0, head)
  }

  /**
    * 插入結點
    *
    * @param value 結點值
    * @param index 座標
    * @param len   當前所在深度
    * @param cur   當前所在節點
    */
  def add(value: Int, index: Int, len: Int, cur: Node): Unit = {
    if (index > length) {
      println("現有 " + length + "個元素" + ",無法插入座標" + index)
      return
    }
    if (index == len) {
      val newNode = new Node //創建新節點
      newNode.value = value //賦值
      newNode.next = cur.next //掛載到鏈表上
      cur.next = newNode
      length += 1
    } else {
      add(value, index, len + 1, cur.next) //遞歸調用-處理下一個節點
    }
  }

  /**
    * 根據座標查詢數據
    *
    * @param index
    * @return
    */
  def get(index: Int): Int = {
    get(index, 0, head)
  }

  /**
    * 根據座標查詢數據
    *
    * @param index 座標
    * @param len   當前深度
    * @param cur   當前節點
    * @return
    */
  def get(index: Int, len: Int, cur: Node): Int = {
    if (index > length - 1) {
      throw new IllegalArgumentException("查詢座標存在")
    }
    if (index == len) {
      //以頭結點開始,所以下個節點纔是數據節點
      return cur.next.value
    } else {
      get(index, len + 1, cur.next)
    }
  }

  /**
    * 根據座標刪除節點
    * @param index
    * @return
    */
  def remove(index: Int): Int = {
     remove(index,0,head)
  }

  /**
    * 根據座標刪除節點
    * @param index  座標
    * @param len    深度
    * @param cur    當前節點
    * @return       刪除值
    */
  def remove(index: Int, len: Int, cur: Node): Int = {
    //座標大於當前鏈表長度
    if (index > length - 1) {
      throw new IllegalArgumentException("刪除座標存在")
    }
    //待刪除節點位置
    if (index == len) {
      val delNode = cur.next //待刪除節點
      cur.next = delNode.next //重新掛載節點
      delNode.next = null //節點刪除
      length -= 1
      delNode.value
    } else {
      //尋找下一個節點
      remove(index, len + 1, cur.next)
    }
  }

  def size() = {
    length
  }

  def isEmpty() = {
    length == 0
  }

  def showData(): Unit = {
    var curNode = head.next
    for (i <- 0 to length - 1) {
      print(curNode.value + "-->")
      curNode = curNode.next
    }
  }
}

class Node {
  var value: Int = _
  var next: Node = null
  var prev:Node = null
}
2、雙向鏈表代碼
object ShuangxLink{
  def main(args: Array[String]): Unit = {
    val link = new ShuangxLink()
    //    (0 to 10).foreach(link.addFirstNode(_))
    (0 to 10).foreach(link.addLastNode(_))
    link.showData()
    println()
    println(link.size())
    println(link.get(3))
    println(link.remove(3))
    println(link.get(3))
    println(link.size())
    link.showData()
  }
}

/**
  *
  * 雙向鏈表:需要頭尾節點,並且可以從尾部向頭結點查找
  * head <--> 1 <--> 4 <--> tail
  *
  * 優點:使用雙向鏈表來完成棧、隊列,則從頭尾節點來操作,省略遍歷鏈表的時間了
  */
class ShuangxLink {
  val head = new Node   //頭結點
  val tail = new Node   //尾結點
  head.next = tail
  tail.prev = head
  //長度
  private var length = 0

  //添加在首位
  def addFirstNode(value: Int): Unit = {
    add(value, 0, 0, head)
  }

  //末尾添加
  def addLastNode(value: Int): Unit = {
    add(value, length, 0, head)
  }

  /**
    * 插入結點
    *
    * @param value 結點值
    * @param index 座標
    * @param len   當前所在深度
    * @param cur   當前所在節點
    */
  def add(value: Int, index: Int, len: Int, cur: Node): Unit = {
    if (index > length) {
      println("現有 " + length + "個元素" + ",無法插入座標" + index)
      return
    }
    if (index == len) {
      val newNode = new Node //創建新節點
      newNode.value = value //賦值
      newNode.next = cur.next //掛載到鏈表上
      newNode.prev = cur

      cur.next.prev = newNode
      cur.next = newNode
      length += 1
    } else {
      add(value, index, len + 1, cur.next) //遞歸調用-處理下一個節點
    }
  }

  /**
    * 根據座標查詢數據
    *
    * @param index
    * @return
    */
  def get(index: Int): Int = {
    get(index, 0, head)
  }

  /**
    * 根據座標查詢數據
    *
    * @param index 座標
    * @param len   當前深度
    * @param cur   當前節點
    * @return
    */
  def get(index: Int, len: Int, cur: Node): Int = {
    if (index > length - 1) {
      throw new IllegalArgumentException("查詢座標存在")
    }
    if (index == len) {
      //以頭結點開始,所以下個節點纔是數據節點
      return cur.next.value
    } else {
      get(index, len + 1, cur.next)
    }
  }

  /**
    * 根據座標刪除節點
    * @param index
    * @return
    */
  def remove(index: Int): Int = {
    remove(index,0,head)
  }

  /**
    * 根據座標刪除節點
    * @param index  座標
    * @param len    深度
    * @param cur    當前節點
    * @return       刪除值
    */
  def remove(index: Int, len: Int, cur: Node): Int = {
    //座標大於當前鏈表長度
    if (index > length - 1) {
      throw new IllegalArgumentException("刪除座標存在")
    }
    //待刪除節點位置
    if (index == len) {
      val delNode = cur.next //待刪除節點
      cur.next = delNode.next //它的前一個節點指向它的後一個節點
      delNode.next.prev = cur //它的後一個節點的前一個節點指向它的前一個節點
      delNode.next = null //節點刪除
      delNode.prev = null
      length -= 1
      delNode.value
    } else {
      //尋找下一個節點
      remove(index, len + 1, cur.next)
    }
  }

  def size() = {
    length
  }

  def isEmpty() = {
    length == 0
  }

  def showData(): Unit = {
    var curNode = head.next
    for (i <- 0 to length - 1) {
      print(curNode.value + "-->")
      curNode = curNode.next
    }
  }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章