算法03_隊列

隊列

隊列介紹
隊列是一個有序列表,可以使用數組或者鏈表來實現
遵循先入先出的原則(先存入隊列的數據,要先取出。後存入的要後取出)
樣例圖(使用數組模型示意圖)
![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20200515221726322.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2x4cHF4bA==,size_16,color_FFFFFF,t_70
隊列本身是有序列表,如上面的圖之中maxSize是該隊列的最大容量開頭,結尾分別記錄隊列前後端的下標(類似索引),開頭會隨着數據的輸出而改變,結尾則是隨着數據的輸入而改變。
小結:
: 1.隊列是有序隊列
: 2.開始初始化爲-1,表示隊列的頭,但是約定不包含頭元素,即指向隊列的第一個元素的前一個位置
: 3.結尾初始化爲-1,表示隊列的尾,但是包含最後這個元素,即指向隊列尾部
: 4.判斷隊列空,開始 == 結尾 表示空
: 5.判斷隊列滿,結尾 == maxSize-1

向隊列加入數據的時候會有兩個步驟

1 將結尾向後移:結尾+1(這個過程要判斷開始結尾是否相等,如果相等隊列爲空)
2 判斷結尾跟maxSize-1:如果結尾小於maxSize-1,則將數據放入到結尾所指向的數組元素中;否則數據無法存入,即結尾 == maxSize(隊列滿了,已達到最大值)

代碼(沒優化前)

import scala.io.StdIn

object test01 {
  def main(args: Array[String]): Unit = {

    val queue = new addDateDemo(3)
    // 菜單演示
    var key = ""
    while (true) {
      println()
      println("請選擇菜單")
      println("show : 顯示隊列")
      println("add  : 添加數據")
      println("get  : 獲取數據")
      println("peek(偷看): 查看頭元素值")
      println("exit : 退出程序")
      key = StdIn.readLine()
      key match {
        case "show" => queue.show()
        case "add" =>
          println("請輸入一個數")
          val num: Int = StdIn.readInt()
          queue.addDate(num)
        case "get" =>
          // 獲取返回值
          val res: Any = queue.getDates()
          // 判斷返回值是否爲空
          if (res.isInstanceOf[Exception]){
            println(res.asInstanceOf[Exception].getMessage)
          }else{
            // 查看隊列元素信息
            printf("隊列取出的值=%d",res)
          }
        case "peek" =>
          // 獲取返回值
          val res: Any = queue.peek()
          // 判斷返回值是否爲空
          if (res.isInstanceOf[Exception]){
            println(res.asInstanceOf[Exception].getMessage)
          }else{
            // 查看頭元素
            printf("隊列當前頭元素的值=%d",res)
          }

      }


    }
  }
}

// 編寫一個數據結構的基本思路  創建-遍歷(查看)-修改-刪除
class addDateDemo(arrMaxSize: Int) {
  // 指定隊列大小
  val maxSize = arrMaxSize
  // 隊列中數據,存放在數組,即數組模擬隊列
  val arr = new Array[Int](maxSize)
  // 初始化開始
  var start = -1
  // 初始化結尾
  var end = -1


  // 判斷隊列是否滿了
  def isFull(): Boolean = {
    end == maxSize - 1
  }

  // 判斷隊列是否爲空
  def isEmpty(): Boolean = {
    start == end
  }

  // 查看隊列的頭元素,但是不取出
  def peek(): Any ={
    if (isEmpty()) {
      return new Exception("隊列爲空,什麼都沒有")
    }
    return arr(start+1) // start不進行+=1
  }

  // 相隊列中添加數據 num
  def addDate(num: Int): Unit = {
    // 如果已經滿了就不能添加進去了
    if (isFull()) {
      println("隊列已滿,無法加入")
      return
    }
    // 隊列沒滿 ,將end後移
    end += 1
    arr(end) = num
  }

  // 遍歷(顯示)
  def show(): Unit = {
    // 先判斷隊列是否爲空
    if (isEmpty()) {
      println("什麼都沒有")
      println()
      return
    }
    // 如果不爲空,遍歷打印結果
    println("隊列數據:")
    for (i <- start + 1 to end) {
      printf("arr(%d)=%d \t", i, arr(i))
    }
    println()
  }

  // 從隊列中取數據, 可能取到數據,可能取不到數據
  def getDates(): Any = {
    if (isEmpty()) {
      return new Exception("隊列爲空,沒有數據")
    }
    // 將start後移
    // 取數據不是把數據刪了,而是不讓我們訪問到了
    // 又因爲隊列前進先出,數據必須從第一個元素(也就是start)開始取,所以+1就不會再看到之前的數據
    start += 1
    return arr(start)
  }


}

效果圖:
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

數組模擬環形隊列

對前面的數組模擬隊列的優化,充分利用數組。因此將數組看做是一個環形的。(通過取模的方式來實現即可)
1.將start初始化爲0,start指向隊列的第一個元素
2.將end初始化爲0,end指向的是隊列的最後一個元素的後一個位置
3.通過%將隊列當做環形,判斷隊列是否爲空通過 start == end
4.判斷隊列元素滿的條件是(end+1)%maxSize=start, +1的原因的預留了一個空間作爲約定

代碼(優化後)

import scala.io.StdIn

object test02 {
  def main(args: Array[String]): Unit = {

    val queue = new addDateDemo2(4)
    // 菜單演示
    var key = ""
    while (true) {
      println()
      println("請選擇菜單")
      println("show : 顯示隊列")
      println("add  : 添加數據")
      println("get  : 獲取數據")
      println("peek(偷看): 查看頭元素值")
      println("exit : 退出程序")
      key = StdIn.readLine()
      key match {
        case "show" => queue.show()
        case "add" =>
          println("請輸入一個數")
          val num: Int = StdIn.readInt()
          queue.addDate(num)
        case "get" =>
          // 獲取返回值
          val res: Any = queue.getDates()
          // 判斷返回值是否爲空
          if (res.isInstanceOf[Exception]) {
            println(res.asInstanceOf[Exception].getMessage)
          } else {
            // 查看隊列元素信息
            printf("隊列取出的值=%d", res)
          }
        case "peek" =>
          // 獲取返回值
          val res: Any = queue.peek()
          // 判斷返回值是否爲空
          if (res.isInstanceOf[Exception]) {
            println(res.asInstanceOf[Exception].getMessage)
          } else {
            // 查看頭元素
            printf("隊列當前頭元素的值=%d", res)
          }

      }


    }
  }
}

// 編寫一個數據結構的基本思路  創建-遍歷(查看)-修改-刪除
class addDateDemo2(arrMaxSize: Int) {
  // 指定隊列大小
  val maxSize = arrMaxSize
  // 隊列中數據,存放在數組,即數組模擬隊列
  val arr = new Array[Int](maxSize)
  // 初始化開始
  var start = 0
  // 初始化結尾
  var end = 0


  // 判斷隊列是否滿了
  def isFull(): Boolean = {
    (end + 1) % maxSize == start
  }

  // 判斷隊列是否爲空
  def isEmpty(): Boolean = {
    start == end
  }

  // 查看隊列的頭元素,但是不取出
  def peek(): Any = {
    if (isEmpty()) {
      return new Exception("隊列爲空,什麼都沒有")
    }
    return arr(start) // start不進行+=1
  }

  // 相隊列中添加數據 num
  def addDate(num: Int): Unit = {
    // 如果已經滿了就不能添加進去了
    if (isFull()) {
      println("隊列已滿,無法加入")
      return
    }
    arr(end) = num
    // 隊列沒滿 ,將end後移
    end = (end + 1) % maxSize
  }


  // 從隊列中取數據, 可能取到數據,可能取不到數據
  def getDates(): Any = {
    if (isEmpty()) {
      return new Exception("隊列爲空,沒有數據")
    }
    // 因爲start指向隊列的第一個元素
    // 先將數據保存到臨時變量中
    val res: Int = arr(start)
    // start 後移
    start = (start + 1) % maxSize
    return res
  }


  // 遍歷(顯示)
  // 從start開始打印,打印多少個元素就可以了,所以需要統計出該隊列有多少個有效元素
  def show(): Unit = {
    // 先判斷隊列是否爲空
    if (isEmpty()) {
      println("什麼都沒有")
      println()
      return
    }

    // 使用取模的方式
    // 如果不爲空,遍歷打印結果
    println("隊列數據:")
    for (elem <- start until start + size()) {
      printf("arr(%d)=%d \t", (elem % maxSize), arr(elem % maxSize))
    }
  }

  // 編寫一個方法,統計當前有多少個元素
  def size(): Int = {
    return (end + maxSize - start) % maxSize
  }

}

效果圖:
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

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