java佇列--先進先出(迴圈佇列、鏈佇列)
阿新 • • 發佈:2018-12-30
佇列: 只允許在一端進行插入操作(隊尾),在另一端進行刪除操作(隊頭)。 佇列的特徵就是: 先進先出。
佇列的思想及實現也同樣非常簡單。在生活中的各種常常都需要排隊進行,鍵盤中快取區、作業系統中的作業排程等都有用到佇列先進先出的思想。在這裡同樣用一個示意圖展示佇列的基本思想。
下面筆者才用陣列儲存元素,實現了一個迴圈佇列。
佇列中最重要的一個方法就是佇列是否滿的判斷,
判斷佇列是否為滿。隊滿: rear + 2 = front 或 front + maxSize -2 = rear
判斷佇列是否為空。隊空: rear + 1 = front 或 front + maxSize -1 = rear
獲取佇列大小(元素個數):可以通過隊頭隊尾計算出佇列的大小,也可以通過一個計數器,當入隊是加1,出隊是減1./** 判斷佇列是否為空。隊空: rear + 1 = front 或 front + maxSize -1 = rear * 通過陣列容量比佇列資料項的最大值大一,來區分對空和對滿。 */ public boolean isEmpty(){ return (rear + 1 == front || front + maxSize -1 == rear); } /**判斷佇列是否為滿。 隊滿: rear + 2 = front 或 front + maxSize -2 = rear * 通過陣列容量比佇列資料項的最大值大一,來區分對空和對滿。 */ public boolean isFull(){ return (rear + 2 == front || front + maxSize -2 == rear); }
/** 獲取佇列的大小
*/
public int queueSize(){
if(rear >= front){
return rear - front +1;
}else {
return maxSize - front + (rear + 1);
}
}
出隊入隊檢視隊頭元素:
入隊 出隊
全部程式碼及測試:
結果package org.TT.Queue; /** * 迴圈佇列: 先進先出 * 佇列同樣是個概念上的輔助工具。這裡採用陣列完成佇列的操作,仍然採用泛型 * 佇列的資料項的入隊、出隊時間複雜度為常數 O(1)。 * 通過隊頭隊尾指標的移動儲存所有資料位置不動,而不是移動資料項。 * 在這裡,陣列的大小比佇列存放資料元素大1,主要是為了方便隊滿的判斷。 */ public class Queue<T> { private int maxSize; // 佇列最多容納數量 private Object[] queueArray; private int front; // 隊頭 private int rear; // 隊尾 private int size; public Queue(int length) { maxSize = length; queueArray = new Object[maxSize]; front = 0; rear = -1; size = 0; } /** 入隊: 先將rear(隊為指標) 加1, 後將資料項存入rear的位置。 * 當rear 指向maxSize -1 的位置時,將rear 設定為-1(迴圈佇列),加1 後存入資料項。 */ public void enQueue(T str){ if(isFull()){ // 入隊之前先檢查佇列是否已滿,已滿則丟擲異常。 throw new RuntimeException("佇列已滿," + str + " 不能入隊!"); } if(rear == maxSize -1){ rear = -1; } queueArray[++rear] = str; // 先將 rear 加1,後取值 size++; } /**出隊: 先取出front 的值,然後將front 減1 * 如果 front 超過了陣列的頂端,將 front 設定為 0(迴圈佇列) */ @SuppressWarnings("unchecked") public T deQueue(){ if(isEmpty()){ // 出隊之前先檢查佇列是否為空, 為空則丟擲異常。 throw new RuntimeException("佇列為空,不能出隊!"); } T str = (T) queueArray[front++]; // 先去 queueArray[front] 的值,後將front 加1 if(front == maxSize){ front = 0; } size--; return str; } /**檢視對頭資料項 */ @SuppressWarnings("unchecked") public T peek(){ if(isEmpty()){ // 檢視隊頭時,判斷是否為空, 為空則丟擲異常。 throw new RuntimeException("佇列為空!"); } return (T) queueArray[front]; } /** 判斷佇列是否為空。隊空: rear + 1 = front 或 front + maxSize -1 = rear * 通過陣列容量比佇列資料項的最大值大一,來區分對空和對滿。 */ public boolean isEmpty(){ return (rear + 1 == front || front + maxSize -1 == rear); } /**判斷佇列是否為滿。 隊滿: rear + 2 = front 或 front + maxSize -2 = rear * 通過陣列容量比佇列資料項的最大值大一,來區分對空和對滿。 */ public boolean isFull(){ return (rear + 2 == front || front + maxSize -2 == rear); } /** 獲取佇列的大小 */ public int queueSize(){ /* 可以通過隊頭隊尾計算出佇列的大小,也可以通過一個計數器,當入隊是加1,出隊是減1. if(rear >= front){ return rear - front +1; }else { return maxSize - front + (rear + 1); } */ return size; } public static void main(String[] args) { Queue<String> queue = new Queue<>(5); queue.enQueue("a"); queue.enQueue("b"); queue.enQueue("c"); queue.enQueue("d"); queue.deQueue(); queue.deQueue(); System.out.println("佇列是否為空: " + queue.isEmpty() + " 佇列是否滿: " + queue.isFull()); System.out.println("佇列大小:" + queue.queueSize()); int size = queue.queueSize(); for(int i = 0; i < size; i++){ String str = queue.deQueue(); System.out.print(str + " "); } } }
關於鏈佇列只是在單鏈表的基礎上多了簡單的修改,在單鏈表中新增一個尾指標即可,每次入隊、出隊只分別對單鏈表的隊尾和隊首進行插入和刪除在操作,由於鏈隊沒有隊滿的限制,所以相對於非常簡單,而判空操作只需判斷 front == rear 是否成立。 在這裡筆者就不列出鏈佇列。在java庫中也有佇列相關的介面及實現並且還有雙端佇列、優先佇列等類。