爲充分利用向量空間,克服"假溢出"現象的方法是:將向量空間想象爲一個首尾相接的圓環,並稱這種向量爲循環向量。存儲在其中的隊列稱爲循環隊列。循環隊列是把順序隊列首尾相連,把存儲隊列元素的表從邏輯上看成一個環,成爲循環隊列。
循環隊列就是將隊列存儲空間的最後一個位置繞到第一個位置,形成邏輯上的環狀空間,供隊列循環使用。在循環隊列結構中,當存儲空間的最後一個位置已被使用而再要進入隊運算時,只需要存儲空間的第一個位置空閒,便可將元素加入到第一個位置,即將存儲空間的第一個位置作爲隊尾。 循環隊列可以更簡單防止僞溢出的發生,但隊列大小是固定的。
在循環隊列中,當隊列爲空時,有front=rear,而當所有隊列空間全佔滿時,也有front=rear。爲了區別這兩種情況,規定循環隊列最多只能有MaxSize-1個隊列元素,當循環隊列中只剩下一個空存儲單元時,隊列就已經滿了。因此,隊列判空的條件是front=rear,而隊列判滿的條件是front=(rear+1)%MaxSize。
package queue;
import java.util.Scanner;
public class CircleArrayQueueDemo
{
public static void main(String[] args)
{
//測試一把
System.out.println("測試數組模擬環形隊列的案例~~~");
// 創建一個環形隊列
CircleArray queue = new CircleArray(4); //說明設置4, 其隊列的有效數據最大是3
char key = ' '; // 接收用戶輸入
Scanner scanner = new Scanner(System.in);//
boolean loop = true;
// 輸出一個菜單
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): 查看隊列頭的數據");
while (loop)
{
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) {
// TODO: handle exception
System.out.println(e.getMessage());
}
break;
case 'h': // 查看隊列頭的數據
try {
int res = queue.headQueue();
System.out.printf("隊列頭的數據是%d\n", res);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
break;
case 'e': // 退出
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出~~");
}
}
class CircleArray
{
private int maxSize; //表示數組的最大容量
//front就是指隊列的第一個元素,也就是說arr[front]就是隊列的第一個元素
private int front;
//rear指向隊列的最後一個元素的後一個位置,因爲希望空出一個空間做約定
//rear的初始值爲0
private int rear; //隊列尾
private int[] arr;//該數組模擬隊列,用於存放數據
//構造器
public CircleArray(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] = n;
//將rear後移,這裏必須要考慮取模
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 + size();i++)
{
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i%maxSize]);
}
}
//求出當前隊列的有效數據的個數
public int size()
{
//rear=2;
//front=0;
//maxSize=3;
return (rear + maxSize - front) % maxSize;
}
//顯示隊列的頭數據
public int headQueue()
{
//判斷
if(isEmpty())
{
throw new RuntimeException("隊列爲空,沒有數據~");
}
return arr[front];
}
}