1. 程式人生 > 實用技巧 >java資料結構與演算法二: 佇列(陣列模擬環形佇列)

java資料結構與演算法二: 佇列(陣列模擬環形佇列)

佇列:陣列模擬環形佇列

一、思路分析

對之前的陣列模擬佇列的優化,充分利用陣列,將陣列看作是一個環形(通過取模的方式來實現即可

分析說明:

  • front變數的含義做一個調整:front指向佇列的第一個元素,也就是說arr[front]就是佇列的第一個元素,front的初始值為0

  • rear變數的含義做一個調整:rear指向佇列的最後一個元素的後一個位置,因為希望空出一個空間做為約定,rear的初始值為0

  • 當佇列滿時,條件是(rear + 1) % maxSize = front 【滿】

  • 當佇列為空的條件,rear == front【空】

  • 當我們這樣分析,佇列中有效的資料的個數為:(rear + maxSize - front) % maxSize

  • 我們就可以再原來的佇列上修改得到一個環形佇列

二、程式碼實現

public class CircleArrayQueue {

	public static void main(String[] args) {
		//測試
		System.out.println("測試陣列模擬環形佇列的案例~");
		//建立一個佇列
		CircleArray arrayQueue = new CircleArray(4);	//設定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':	//顯示佇列
				arrayQueue.showQueue();
				break;
			case 'a':	//新增資料
				System.out.println("輸出一個數");
				int value = scanner.nextInt();
				arrayQueue.addQueue(value);
				break;
			case 'g':	//取出資料
				try {
					int res = arrayQueue.getQueue();
					System.out.printf("取出的資料是%d\n",res);
				} catch (Exception e) {
					// TODO: handle exception
					System.out.println(e.getMessage());
				}
				break;
			case 'h':	//檢視佇列頭的資料
				try {
					int res = arrayQueue.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變數的含義做一個調整:front就指向佇列的第一個元素,也就是說arr[front]就是佇列的第一個元素
	//front的初始值=0
	private int front;	
	//rear變數的含義做一個調整:rear指向佇列的最後一個元素的後一個位置,因為希望空出一個空間做為約定
	//rear的初始值=0
	private int rear; 
	private int[] arr; //該資料用於存放資料,模擬佇列
	
	public CircleArray(int arrMaxSize) {
		super();
		this.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;
		}
		//思路:從front開始遍歷,遍歷多少個元素
		for(int i = front; i < front + size(); i++) {
			System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);
		}
	}
	
	//求出當前佇列有效資料的個數
	public int size() {
		return (rear + maxSize -front) % maxSize;
	}
	
	//顯示佇列的頭資料,注意不是取出資料
	public int headQueue() {
		//判斷
		if(isEmpty()) {
			throw new RuntimeException("佇列為空,沒有資料~");
		}
		return arr[front];
	}
}