隊列:是限只容許在一端進行插入操做,而在另外一端進行刪除操做的線性表
。java
先進先出
原則,簡稱FIFO隊列也有相似線性表的各類操做,不一樣的是算法
實際場景:銀行叫號排隊數組
package com.queue; /** * 普通隊列只是一次性儲存 * 不能複用前面的空間 * front指向第一個元素的【前面】! * rear指向最後一個元素 * 判斷空,兩指針相等 * 判斷滿,尾指針指向最大下標 */ public class ArrayQueue { private int maxSize; private int front; private int rear; private int[] arr; // 建立隊列的構造器 public ArrayQueue(int maxSize) { this.maxSize = maxSize; // 建立指定長度的數組模擬隊列 arr = new int[maxSize]; // 指向隊列頭部,不包含那個數,好比指向0,實際:下標1纔是隊列頭 this.front = -1; // 指向隊列尾部,包含!好比指向10,實際:下標10就是隊尾 this.rear = -1; } /** * 判斷隊列是否滿 * 無參 * @return */ public boolean isFull() { return rear == maxSize - 1; } /** * 判斷隊列是否空 * 無參 * @return */ public boolean isEmpty() { return rear == front; } /** * 入隊 * * @param n 添加的數據 */ public void addQueue(int n) { // 首先判斷是否滿 if (isFull()) { System.out.println("隊列已滿,沒法加入"); return; } // 尾指針後移 rear++; arr[rear] = n; } /** * 出隊 * @return */ public int getQueue() { // 先判斷是否爲空 if (isEmpty()) { throw new RuntimeException("隊列爲空,不能取數據"); } // 頭指針後移 front++; return arr[front]; } /** * 打印隊列中的有效數據 * */ public void show() { // 遍歷 if (isEmpty()) { System.out.println("隊列爲空"); return; } for (int i = front + 1; i <= rear; i++) { System.out.print(arr[i] + "\t"); } } /** * 不是出隊入隊 * @return 返回隊首元素 */ public int headQueue() { // 先判斷是否爲空 if (isEmpty()) { throw new RuntimeException("隊列爲空,不能取數據"); } return arr[front + 1]; } /** * 不是出隊入隊 * @return 返回隊尾元素 */ public int tailQueue() { // 先判斷是否爲空 if (isEmpty()) { throw new RuntimeException("隊列爲空,不能取數據"); } return arr[rear]; } }
package com.queue; import java.util.Scanner; public class Application { public static void main(String[] args) { // 建立一個隊列,最大儲存4個元素 ArrayQueue queue = new ArrayQueue(4); Scanner sc = new Scanner(System.in); int op = -1; do { System.out.println("請選擇測試功能"); System.out.println("1.顯示隊列"); System.out.println("2.入隊操做"); System.out.println("3.出隊操做"); System.out.println("4.查看頭元素"); System.out.println("5.查看尾元素"); System.out.println("0.退出"); op = sc.nextInt(); switch (op) { case 1: System.out.print("隊列中的數據:"); queue.show(); break; case 2: System.out.print("請輸入入隊元素:"); int n = sc.nextInt(); queue.addQueue(n); System.out.print("隊列中的數據:"); queue.show(); break; case 3: try { queue.getQueue(); System.out.print("隊列中的數據:"); queue.show(); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 4: try { System.out.println("隊頭元素"+queue.headQueue()); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 5: try { System.out.println("隊尾元素"+queue.tailQueue()); } catch (Exception e) { System.out.println(e.getMessage()); } break; default: break; } System.out.println(); System.out.println(); } while (op != 0); System.out.println("測試結束"); } }
把隊列頭尾相接的順序存儲結構稱爲循環隊列測試
對前面的隊列存在「假溢出」的問題進行優化,充分利用數組優化
將數組當作一個環形的,經過取模的方式便可實現。this
package com.queue; /** * 循環隊列能夠充分利用空間 * front 指向隊列的【第一個】元素 * rear 指向最後一個元素的【後一個】 * 判斷爲【空】 rear == front * 判斷爲【滿】(rear + 1)% maxSize == front */ public class CircleArrayQueue { private int maxSize; private int front; private int rear; private int[] arr; // 建立隊列的構造器 public CircleArrayQueue(int maxSize) { this.maxSize = maxSize; // 建立指定長度的數組模擬隊列 arr = new int[maxSize]; // 指向隊列頭部,包含那個數 this.front = 0; // 指向隊列尾部的後一個 this.rear = 0; } /** * 判斷隊列是否滿 * 無參 * * @return */ public boolean isFull() { return (rear + 1) % maxSize == front; } /** * 判斷隊列是否空 * 無參 * * @return */ public boolean isEmpty() { return rear == front; } /** * 入隊 * @param n 添加的數據 */ public void addQueue(int n) { // 首先判斷是否滿 if (isFull()) { System.out.println("隊列已滿,沒法加入"); return; } // 先入隊再後移 arr[rear] = n; // rear++ 會出現下標溢出 rear = (rear + 1) % maxSize; } /** * 出隊 * @return 返回隊列第一個元素,同時指針後移 */ public int getQueue() { // 先判斷是否爲空 if (isEmpty()) { throw new RuntimeException("隊列爲空,不能取數據"); } // 頭指針後移 int value = arr[front]; front = (front + 1) % maxSize; return value; } /** * 打印隊列中的有效數據 */ public void show() { // 遍歷 if (isEmpty()) { System.out.println("隊列爲空"); return; } for (int i = front ; i < front + size(); i++) { // i 可能會溢出,因此要取模循環 int idx = i % maxSize; System.out.print(arr[idx] + "\t"); } } public int size() { return (rear + maxSize -front)%maxSize; } /** * 不是出隊入隊 * * @return 返回隊首元素 */ public int headQueue() { // 先判斷是否爲空 if (isEmpty()) { throw new RuntimeException("隊列爲空,不能取數據"); } return arr[front]; } /** * 不是出隊入隊 * * @return 返回隊尾元素 */ public int tailQueue() { // 先判斷是否爲空 if (isEmpty()) { throw new RuntimeException("隊列爲空,不能取數據"); } return arr[rear-1]; } }
測試代碼指針
package com.queue; import java.util.Scanner; public class Application { public static void main(String[] args) { // 建立一個隊列,最大儲存4個元素 // ArrayQueue queue = new ArrayQueue(4); // 建立一個循環隊列,須要留出一個空位判斷是否滿,因此最大儲存4個元素 CircleArrayQueue queue = new CircleArrayQueue(5); Scanner sc = new Scanner(System.in); int op = -1; do { System.out.println("請選擇測試功能"); System.out.println("1.顯示隊列"); System.out.println("2.入隊操做"); System.out.println("3.出隊操做"); System.out.println("4.查看頭元素"); System.out.println("5.查看尾元素"); System.out.println("0.退出"); op = sc.nextInt(); switch (op) { case 1: System.out.print("隊列中的數據:"); queue.show(); break; case 2: System.out.print("請輸入入隊元素:"); int n = sc.nextInt(); queue.addQueue(n); System.out.print("隊列中的數據:"); queue.show(); break; case 3: try { queue.getQueue(); System.out.print("隊列中的數據:"); queue.show(); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 4: try { System.out.println("隊頭元素"+queue.headQueue()); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 5: try { System.out.println("隊尾元素"+queue.tailQueue()); } catch (Exception e) { System.out.println(e.getMessage()); } break; default: break; } System.out.println(); System.out.println(); } while (op != 0); System.out.println("測試結束"); } }
區別 | 普通隊列 | 循環隊列 |
---|---|---|
指針 | 指針向前(front指向前一個) | 指針向後(rear指向後一個) |
初始值 | 兩個都是-1 | 兩個都是0 |
判斷空 | rear == front | rear == front |
判斷滿 | rear == maxSize -1 | (rear + 1) % maxSize == front |
指針後移 | ++ | 加1取模 |
隊列元素個數 | rear-front | rear -front 或 (rear - 0) + (maxSize - front) 合併公式 (rear + maxSize - front) % maxSize |
隊列的鏈式存儲結構,其實就是線性表的單鏈表,只不過它只能尾進頭出而已,簡稱爲鏈隊列。code
爲了操做上的方便,咱們將隊頭指針指向鏈隊列的頭結點,blog
package com.queue; public class LinkQueue { // 隊頭指針,隊尾指針 private QNode front; private QNode rear; public LinkQueue() { //初始化頭結點 front = new QNode(); rear = front; } public boolean isEmpty() { return front == rear; } public void addQueue(int num) { QNode qNode = new QNode(num); rear.next = qNode; rear = qNode; } public int delQueue() { if (isEmpty()) { throw new RuntimeException("隊空了"); } // 第一個結點沒有數據 int value = front.next.data; // 頭結點要一直保留,跳過第一個有數據的結點 front.next = front.next.next; // 若是無數據結點,尾指針歸位。 if (front.next == null) { rear = front; } return value; } public void list() { if (isEmpty()) { System.out.println("隊空了"); } QNode temp = front.next; while (temp != null) { System.out.print(temp.data + "\t"); temp = temp.next; } } } class QNode{ public int data; public QNode next; public QNode() {} public QNode(int data) { this.data = data; } }
棧和隊列都是特殊的線性表,只不過對插入和刪除操做作了限制隊列
棧:是限定僅在表尾進行插入和刪除操做的線性表
隊列:是隻容許在一端進行插入操做,在另外一端進行刪除操做的線性表
他們都可用線性表的順序存儲結構實現,都存在則順序存儲的一些弊端。
也均可以經過鏈式存儲結構實現,原則上與線性表基本相同。