隊列的一個使用場景
銀行排隊的案例:
隊列介紹
隊列是一個有序列表,可以用數組或是鏈表來實現。
遵循先入先出的原則。即:先存入隊列的數據,要先取出。後存入的要後取出
示意圖:(使用數組模擬隊列示意圖)
數組模擬隊列
隊列本身是有序列表,若使用數組的結構來存儲隊列的數據,則隊列數組的聲明如下圖, 其中 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)
}
}
}
}
}
測試代碼
發現從數組隊列中取出元素後還能再插入元素