在我上一個博客中,我們提到數組實現隊列時,不能實現代碼的複用,優化方法是可以改成一個環形的數組(進行取餘)。所以本次我將總結如何用數組實現環形隊列。
思路:
1、對front變量進行一個調整:front指向隊列的第一個元素,即arr[front]爲隊列的第一個元素;front=0
2、對rear變量也進行相應的調整:reart指向隊列最後一個元素的後一個位置,預留一個空間;rear=0
3、隊滿:(rear+1) % maxSize = front
4、對空:rear == front
5、隊列中的有效數據:(rear + maxSize - front) % maxSize
(rear可能小於maxSize,取餘是爲了獲取在環形隊列上真實位置)
具體實現代碼如下:
(1)、判斷隊列是否滿
(2)、判斷隊列是否爲空
(3)、添加數據到隊列中
(4)、獲取隊列的數據,出隊列;
(5)、顯示當前隊列數據;
(6)、顯示隊列的頭數據,注意不是取出數據;
package com.ycx.queue;
import java.util.Scanner;
public class CircleArrayQueueDemo {
public static void main(String[] args) {
//測試
System.out.println("測試數組模擬環形隊列");
//創建一個環形隊列
CircleArray queue = new CircleArray(4);//有一個空位置 有效數據最大是3
char key = ' ';//接受用戶輸入
Scanner input = new Scanner(System.in);
boolean flag = true; //控制循環 默認死循環
//輸出菜單
while (flag){
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=input.next().charAt(0);//接受收一個字符
switch (key){
case 's':
queue.showQueue();
break;
case 'a':
System.out.println("輸一個數");
int val=input.nextInt();
queue.addQueue(val);
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': //退出程序
input.close();//關閉
flag=false;
break;
default:
break;
}
}
System.out.println("程序退出");
}
}
class CircleArray{
private int maxSize;
//表示數組的最大容量
private int front;
//front變量含義做一個調整:指向隊列的第一個元素,arr[front]即爲隊列的第一個元素
//front=0
private int rear;
//rear變量含義做一個調整:rear指向隊列的最後一個元素的後一個位置,預留一個位置
//rear=0
private int[] arr;
// 該數組用於存放數據,模擬隊列
public CircleArray(int arrMaxSize){
maxSize = arrMaxSize;
arr = new int[maxSize];
front=0;
rear=0;
}
//1.判斷隊列是否滿
public boolean isFull(){
return (rear+1)%maxSize==front;
}
//2.判斷隊列是否爲空
public boolean isEmpty(){
return rear==front;
}
//3.添加數據到隊列中
public void addQueue(int n) {
//判斷隊列是否爲滿
if (isFull()) {
System.out.println("隊列已滿,不能加入數據");
}
arr[rear] = n;
//直接將數據加入 因爲rear本身指的就是 後一個元素
rear = (rear + 1) % n;
//將rear 後移 並取模 (環形 當rear走到最後一個位置時,取模就可以到前面的位置)
}
//4.獲取隊列的數據,出隊列
public int getQueue(){
if(isEmpty()){
throw new RuntimeException("隊列空,不能取數據");
}
//這裏需要分析出front是指向隊列的第一個元素
//①. 先把front對應的值保留到一個臨時變量;
//②. 將front後移,考取取模(因爲front也可能走到最後一個元素,就會越界)
//③. 將臨時保存的變量返回
int value = arr[front];
front = (front+1) % maxSize;
return value;
}
//5.顯示當前隊列數據
public void showQueue() {
//遍歷
if(isEmpty()){
System.out.println("當前隊列爲空");
return;
}
//思路: 從front開始遍歷 一共有front+有效數據個數
for (int i = front ;i <front+size(); i++) {
System.out.printf("arr[%d]=%d\n",i%maxSize,arr[i%maxSize]); //格式化輸出
// i可能也會超出下標(環形)
}
}
//求出當前有效數據個數
public int size(){
return (rear+maxSize-front)%maxSize;
// rear=1 front=0 maxSize=3
}
//6.顯示隊列的頭數據,注意不是取出數據
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("隊列爲空");
}
return arr[front]; //注意:front本身就指向第一個元素
}
}
運行結果如下: