循環隊列的定義
普通的隊列有許多的不足,常常有出現“假溢出”這種現象;但是,循環隊列恰好可以解決這些問題。
循環隊列解決假溢出的辦法是後面滿了,就再從頭開始,也就是頭尾相接的循環。我們把隊列的這種頭尾相接的順序存儲結構稱爲循環隊列。
循環隊列用到的公式:
隊列滿的公式:(rear+1)%QueueSize == front
隊列長度公式:(rear-front+QueueSize)%QueueSize
front:隊列頭,指向隊列的第一個元素, 也就是說 arr[front] 就是隊列的第一個元素,初始值爲 0
rear:隊列尾,指向隊列的最後一個元素的後一個位置,因爲希望空出一個空間做爲約定,初始值爲0
QueueSize:表示數組的最大容量
循環隊列圖解:
假設我們初始化一個QueueSize = 5 的循環隊列(因爲下標從0開始),此時front和rear的值都爲0;
當我們往隊列放入4個數據後,此時的隊列已經滿了(保留一個元素空間)
此時代入隊列滿的公式進行驗算:(4+1)%5 == 0 ;顯而易見,公式左邊5%5結果爲0;公式右邊front的值也爲0;所以該公式驗算結果爲隊列滿。
此時再代入求隊列長度的公式進行驗算:(4-0+5)%5 = 4,求得結果爲4,驗算正確。
當a1、a2出隊,併入隊a5、a6後,就是下圖的樣子
循環隊列代碼實現
package com.Lindom.數據結構.隊列;
import java.util.Scanner;
public class CircleArrayQueue02 {
public static void main(String[] args) {
//創建一個隊列
CircleArrayQueue queue = new CircleArrayQueue(4);
char key; //接收用戶輸入
Scanner scanner = new Scanner(System.in);
boolean loop = true;
//輸入一個菜單
while (loop) {
System.out.println("s(show): 顯示隊列");
System.out.println("e(exit): 退出程序");
System.out.println("a(add): 添加數據到隊列");
System.out.println("g(get): 從隊列取出數據");
System.out.println("h(head): 查看隊列頭的數據");
key = scanner.next().charAt(0);
switch (key){
case 's':
queue.showQueue();
break;
case 'a':
System.out.println("請輸入一個數");
int value = scanner.nextInt();
queue.addQueue(value);
break;
case 'g':
try {
int res = queue.getQueue();
System.out.printf("取出的數據是%d\n",res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int res = queue.headQueue();
System.out.printf("隊列頭的數據是%d\n",res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close();
loop =false;
break;
default:
System.out.println("您輸入的指令無效!請重新輸入:");
break;
}
}
System.out.println("程序退出啦!");
}
}
//使用模擬隊列編寫ArrayQueue類
class CircleArrayQueue{
private int maxSize; //表示數組的最大容量
//front 隊列頭 變量的含義做一個調整: front 就指向隊列的第一個元素, 也就是說 arr[front] 就是隊列的第一個元素
//初始值爲 0
private int front;
//rear 隊列尾 變量的含義做一個調整:rear 指向隊列的最後一個元素的後一個位置. 因爲希望空出一個空間做爲約定.
//的初始值 = 0
private int rear;
private int[] arr; //該數組用於存放數據,模擬隊列
//創建隊列的構造器
public CircleArrayQueue(int arrMaxSize){
maxSize = arrMaxSize;
arr = new int[maxSize];
}
//判斷隊列是否滿
public boolean isFull(){
return (rear + 1) % maxSize == front;
}
//判斷隊列是否爲空
public boolean isEmpty(){
return rear ==front;
}
//添加數據到隊列
public void addQueue(int n){
//判斷隊列是否爲滿
if (isFull()){
System.out.println("隊列滿,不能加入數據!");
return;
}
// arr[rear % maxSize] = n; //一開始想出的這兩行代碼不可行,有bug,後期無法判斷隊列是否爲空
// rear++;
arr[rear] = n;
rear = (rear + 1) % maxSize;
}
//獲取隊列數據,出隊列
public int getQueue(){
//判斷隊列是否爲空
if (isEmpty()) {
//通過拋出異常
throw new RuntimeException("隊列空,不能獲取數據");
}
// 這裏需要分析出 front 是指向隊列的第一個元素
// 1. 先把 front 對應的值保留到一個臨時變量
// 2. 將 front 後移, 考慮取模
// 3. 將臨時保存的變量返回
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
//顯示隊列的所有數據
public void showQueue(){
//遍歷
if (isEmpty()) {
System.out.println("隊列爲空,沒有數據");
return;
}
for (int i = front; i < front + getSize(); i++) {
System.out.printf("arr[%d]=%d\n" , i % maxSize ,arr[i % maxSize]);
}
}
public int getSize(){
return (maxSize - front + rear) % maxSize;
}
//顯示隊列的頭數據,注意不是取出數據
public int headQueue(){
//判斷隊列是否爲空
if (isEmpty()) {
throw new RuntimeException("隊列爲空,沒有數據");
}
return arr[front];
}
}
以上就是代碼的運行過程!希望本文章對你有所幫助!