Scala數據結構和算法:隊列、隊列使用場景、數組模擬隊列、數組模擬環形隊列、隊列圖解

隊列的一個使用場景

銀行排隊的案例:
在這裏插入圖片描述

隊列介紹

隊列是一個有序列表,可以用數組或是鏈表來實現。
遵循先入先出的原則。即:先存入隊列的數據,要先取出。後存入的要後取出
示意圖:(使用數組模擬隊列示意圖)
在這裏插入圖片描述

數組模擬隊列

隊列本身是有序列表,若使用數組的結構來存儲隊列的數據,則隊列數組的聲明如下圖, 其中 maxSize 是該隊列的最大容量。

因爲隊列的輸出、輸入是分別從前後端來處理,因此需要兩個變量 front及 rear分別記錄隊列前後端的下標,front 會隨着數據輸出而改變,而 rear則是隨着數據輸入而改變,如圖所示:
在這裏插入圖片描述

當我們將數據存入隊列時稱爲”addQueue”,addQueue 的處理需要有兩個步驟:思路分析
將尾指針往後移:rear+1 , 當front == rear 【空】
若尾指針 rear 小於隊列的最大下標 maxSize-1,則將數據存入 rear所指的數組元素中,否則無法存入數據。
rear == maxSize - 1[隊列滿]

代碼實現
問題分析並優化

class ArrayQueue(arrMaxSize: Int) { val maxSize: Int = arrMaxSize
  val array = new Array[Int](arrMaxSize)
  var front: Int = -1
  var rear: Int = -1
}
 //初始化
 val queue = new ArrayQueue(3)

rear 是隊列最後[含]
front 是隊列最前元素[不含]

數組模擬隊列

出隊列操作getQueue
顯示隊列的情況showQueue
查看隊列頭元素headQueue
退出系統exit

將原來的隊列的查看隊列頭元素的代碼寫完.

數組模擬環形隊列

對前面的數組模擬隊列的優化,充分利用數組. 因此將數組看做是一個環形的。(通過取模的方式來實現即可)

分析說明:
尾索引的下一個爲頭索引時表示隊列滿,即將隊列容量空出一個作爲約定,這個在做判斷隊列滿的時候需要注意 (rear + 1) % maxSize == front 滿]
rear == front [空]

(cq.rear + cq.maxSize – cq.front) % cq.maxSize

class CircleQueue {
  private int maxSize;
  private int[] arr; // 該數組存放數據,模擬隊列
  private int front; // 指向隊列頭部
  private int rear; // 指向隊列的尾部
  public CircleArrayQueue(int arrMaxSize) {
  	maxSize = arrMaxSize;
	arr = new int[maxSize];
   } 
  public boolean isFull()  {
    //尾索引的下一個爲頭索引時表示隊列滿,即將隊列容量空出一個作爲約定(!!!)
    return (rear + 1) % maxSize == front; }
  public boolean isEmpty()  {
    this.tail == this.head }

   public void addQueue(int n) {
   if (isFull()) {
	System.out.println("隊列滿,無法加入..");
	return;}
	arr[rear] = n;
	rear = (rear + 1) % maxSize;}  
    public int getQueue() {
  	if (isEmpty()) {
		throw new RuntimeException("隊列空~");}
		int value = arr[front];
		front = (front + 1) % maxSize;
		return value;}
  //計算隊列有多個元素
  public int size()  {
    return (rear + maxSize - front) % maxSize;}}

小結

隊列是有序列表
front 初始化爲-1, 表示隊列的頭,但是約定不包含頭元素, 即指向隊列的第一個元素的前一個位置.
rear 初始化-1, 指向隊列尾部,包含最後這個元素
判斷隊列空,front == rear 表示空
判斷隊列滿, rear == maxSize -1

隊列圖解

在這裏插入圖片描述

隊列代碼

package datastructure

import scala.io.StdIn

/**
  * 環形隊列
  * 如果不使用環形隊列,則從隊列中取出元素時不會釋放隊列的使用空間
  * @author cherry
  * @create 2019-09-17-22:45
  */
class CircleArrayQueueDemo(arrMaxSize: Int) {
  val maxSize = arrMaxSize // 指定隊列的大小
  val arr = new Array[Int](maxSize) // 隊列中數據,存放在數組,即數組模擬隊列
  //front 初始化爲0, 表示隊列的頭,指向隊列的第一個元素
  var front = 0
  //rear 初始化0, 指向隊列最後這個元素的後一個位置
  var rear = 0

  //判斷隊列空
  def isEmpty(): Boolean = rear == front

  //判斷滿
  def isFull(): Boolean = (rear + 1) % maxSize == front

  //添加數據到隊列
  def addQueue(num: Int): Unit = {
    if (isFull()) {
      println("隊列滿,不能加入")
      return
    }
    arr(rear) = num
    //將rear 後移
    rear = (rear + 1) % maxSize
  }

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

  //遍歷顯示隊列, 動腦筋
  //思路
  // 1. 從front 開始打印,打印多少個元素
  // 2. 所以,需要統計出該隊列有多少個有效元素
  def show(): Unit = {
    if (isEmpty()) {
      println("隊列空")
      return
    }
    //這裏使用%方式解決
    for (i <- front until front + size()) {
      printf("arr(%d)=%d \t", i % maxSize, arr(i % maxSize))
    }
  }

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

  //查看隊列的頭元素,但是不取出
  def peek(): Any = {
    if (isEmpty()) return new Exception("隊列空,無數據")
    arr(front) //front 不要動
  }


}

object CircleArrayQueueDemo {
  def main(args: Array[String]): Unit = {
    //測試一把
    val queue = new CircleArrayQueueDemo(4)
    //菜單演示
    var key = ""

    while (true) {
      print("請選擇菜單:show: 顯示隊列;add : 添加數據;get : 獲取數據;peek : 取出數據;exit: 退出程序:")
      println()
      key = StdIn.readLine()
      key match {
        case "show" => queue.show()
        case "add" =>
          println("請輸入一個數")
          val num = StdIn.readInt()
          queue.addQueue(num)
        case "get" =>
          //對取回的值,進行判斷
          val res = queue.getQueue()
          //如果是異常
          if (res.isInstanceOf[Exception]) {
            println(res.asInstanceOf[Exception].getMessage)
          } else {
            //Int
            printf("隊列取出的值=%d", res)
          }
        case "peek" =>
          //查看頭元素值,進行判斷
          val res = queue.peek()
          //如果是異常
          if (res.isInstanceOf[Exception]) {
            println(res.asInstanceOf[Exception].getMessage)
          } else {
            //Int
            printf("隊列當前頭元素=%d", res)
          }

      }
    }
  }
}

測試代碼
在這裏插入圖片描述
發現從數組隊列中取出元素後還能再插入元素

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