1. 程式人生 > >【小白學演算法】3. 佇列

【小白學演算法】3. 佇列

### 一、什麼是佇列 * 佇列是一個有序列表,可以用陣列或者連結串列來實現。 * 遵循**先入先出**的原則,即:先存入佇列的資料,要先取出。後存入的的資料,後取出。 看一張佇列的模擬圖,1,2,3表示同一個佇列Queue。 在佇列中有2個指標,front表示隊首,rear表示隊尾。 1. 圖1中表示佇列裡還沒有資料,所以front跟rear初始化都是-1。 2. 當圖2中有資料進行存入的時候,front沒變,而rear則隨著資料的增多而改變。存入了4個數據,於是rear=3。 3. 再看圖3,front變成了2,rear沒有變化,因為前面的2個數據被依次先取出,所以隊首就變成了2。 ![](https://img2020.cnblogs.com/blog/1268169/202103/1268169-20210309232240544-666329948.png) 這就是佇列的“先進先出”了。 ### 二、用陣列來模擬佇列 思路也比較簡單,因為佇列的輸出、輸入是分別從前後端來處理,因此需要兩個變數front以及rear分別記錄佇列的 前後端下標。front會隨著資料輸出而改變,而rear則是隨著資料的輸入而改變。 ``` package sparsearray; import java.util.Scanner; public class MyArrayQueue { public static void main(String[] args) { // 建立一個佇列 ArrayQueue arrayQueue = new ArrayQueue(3); 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", res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'h': try { int headValue = arrayQueue.showHeadQueue(); System.out.printf("隊首資料是:%d", headValue); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'e': scanner.close(); loop = false; break; } } System.out.println("退出程式"); } } // 把佇列抽象成一個類,ArrayQueue class ArrayQueue { //表示陣列最大容量 private int maxSize; // 佇列頭 private int front; // 佇列尾 private int rear; // 用於存放資料的陣列 private int[] arr; // 構造器 public ArrayQueue(int arrMaxSize) { maxSize = arrMaxSize; arr = new int[maxSize]; front = -1; // 指向隊首的前一個位置 rear = -1; // 指向佇列尾部,包括佇列最後的這個資料 } // 判斷佇列是否已經存滿 public boolean isFull() { return rear == maxSize - 1; // 注意這裡的 maxSize-1 為什麼要減1 } // 判斷佇列是否為空 public boolean isEmpty() { return rear == front; } // 新增資料到佇列 public void addQueue(int num) { // 判斷佇列是否滿了 if (isFull()) { System.out.println("佇列已滿,不可加入資料"); return; } rear++; // 讓rear後移 arr[rear] = num; } // 拿出佇列資料 public int getQueue() { // 判斷佇列是否空 if (isEmpty()) { // 丟擲異常 throw new RuntimeException("佇列為空,不可取資料"); } front++; // front後移 return arr[front]; } // 顯示佇列所有資料 public void showQueue() { // 遍歷 if (isEmpty()) { System.out.println("佇列為空"); return; } for (int i = 0; i < arr.length; i++) { System.out.printf("arr[%d]=%d\n", i, arr[i]); } } // 顯示隊裡的隊首資料 public int showHeadQueue() { if (isEmpty()) { // 丟擲異常 throw new RuntimeException("佇列為空,不可取資料"); } return arr[front + 1]; // 注意這裡為甚麼要+1,因為指向隊首的前一個位置 } } ``` 可以用程式碼分別的進行各項操作,看起來似乎沒問題。 但是,實際是有問題。 這裡建立的陣列使用一次就不能接著用了,比如把資料取完後,再往裡加資料就不行了。 所以要對其進行優化,使用演算法,將其改成一個環形佇列,取模:%。 下一章