隊列是一種先進先出(First in First Out)的線性表,簡稱FIFO。隊列中,只容許在一端進行插入操做,而在另外一端進行刪除操做。容許插入的一端稱爲隊尾,容許刪除的一端稱爲隊頭。java
以下圖所示,假設隊列q=(a1,a2,…,an),那麼a1就是隊頭元素,而an是隊尾元素。這樣刪除元素時,老是從a1開始,而插入時,老是在隊列尾部插入。後端
隊列自己是有序列表,若使用數組來存儲隊列的數據,則隊列數組的聲明以下圖所示,其中 maxSize是該隊列的最大容量。由於隊列的輸出、輸入是分別從先後端來處理,所以須要兩個變量front及 rear分別記錄隊列先後端的下標,front 會隨着數據出隊列而改變,而rear則是隨着數據入隊列而改變,以下圖所示:數組
上圖中,變量front與rear的初始值均爲0,這代表front與rear相等時,隊列爲空。當rear==MaxSize成立時,隊列爲滿。須要注意的是,front指向隊列頭部元素位置,而rear指向隊列尾部後一個元素的位置。數據結構
簡單隊列的java實現oop
package com.victor.queue; import java.util.Scanner; //數組模擬簡單隊列 public class ArrayQueueDemo { public static void main(String[] args) { ArrayQueue aq = new ArrayQueue(3); char key = ' '; //接收用戶輸入 Scanner scanner = new Scanner(System.in); boolean loop = true; //輸出一個菜單欄 while(loop){ System.out.println("s(show): 打印隊列"); System.out.println("a(add): 入隊列"); System.out.println("g(get): 出隊列"); System.out.println("h(head): 打印隊頭"); System.out.println("e(exit): 退出程序"); key = scanner.next().charAt(0); switch (key) { case 's': aq.showQueue(); break; case 'a': //入隊列 try { System.out.println("請輸入一個整數"); int value = scanner.nextInt(); aq.addQueue(value); //最好判斷一下value是否是整數 } catch (Exception e) { // TODO: handle exception System.out.println(e.getMessage()); } break; case 'g': //出隊列 try { int res = aq.getQueue(); System.out.printf("出隊列的整數爲%d\n", res); } catch (Exception e) { // TODO: handle exception System.out.println(e.getMessage()); //輸出getQueue()方法中定義好的異常信息 } break; case 'h': //打印隊頭 try { int res = aq.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("程序退出"); } } //使用數組模擬隊列,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 = 0; //隊列頭部 rear = 0; //隊列尾部,指向隊列尾部後一個元素的位置,front=rear時隊列爲空 } //判斷隊列是否爲滿隊列 public boolean isFull(){ return rear == maxSize; } //判斷隊列是否爲空隊列 public boolean isEmpty(){ return rear == front; } //入隊列 public void addQueue(int n){ if(isFull()){ throw new RuntimeException("隊列滿,不能添加數據了"); } arr[rear] = n; rear++; //rear後移 } //出隊列 public int getQueue(){ if(isEmpty()){ //拋出異常 throw new RuntimeException("隊列空,不能出隊列了"); } int value = arr[front]; front++; //front後移 return value; } //打印隊列 public void showQueue(){ if(isEmpty()){ System.out.println("隊列空"); return; } // 打印隊列中的元素,不是打印數組中的全部元素 for (int i = front; i < rear; i++){ System.out.printf("arr[%d]=%d\n",i, arr[i]); //格式化輸出 } } //打印隊頭,不是出隊列 public int headQueue(){ if (isEmpty()){ //拋出異常 throw new RuntimeException("隊列空,不能打印頭"); } return arr[front]; } }
以下圖a所示,當front指向下標爲2的數組位置,rear指向下標爲4的數組位置時,若向隊列尾部再添加一個元素\(a_{5}\),則rear指針會越界,以下圖b所示。但此時隊列前部仍然有空間能夠存儲,因此簡單隊列的弊端就是不能充分利用數組空間。優化
爲了解決數組空間不夠用的辦法就是後面滿了,就再從頭開始,也就是頭尾相接的循環。咱們把隊列的這種頭尾相接的順序存儲結構稱爲循環隊列。好比上圖b中,咱們把rear置爲0便可解決問題。
咱們只需對前面的數組模擬簡單隊列進行優化,便可充分利用數組空間。 所以將數組看作是一個環形的,經過對front和rear指針取模實現指針循環。如下圖爲例進行說明:spa
變化以下:指針
front變量:指向隊列的第一個元素,初始值爲0。移動狀況爲front = (front + 1)% maxSize。code
rear變量:指向隊列的最後一個元素的後一個位置,由於但願空出一個空間作爲約定,rear的初始值爲0。移動狀況爲rear = (rear + 1)% maxSize。blog
當隊列滿時,條件是(rear +1)% maxSize == front成立。由於空出了一個位置,故須要rear+1;
當隊列爲空時,rear == front成立;
隊列中有效數據的個數:這裏有兩種狀況,分別討論:
(1)當front < rear 時,以下圖,隊列中的有效數據個數 = rear - front,這裏rear-front = 2。
(2)當front > rear 時,以下圖,隊列中的有效數據個數=front右邊的數據個數+rear左邊的數據個數,又有:
因此隊列中的有效數據個數 = rear - front + maxSize
綜合兩種狀況可得:
隊列中的有效數據個數 = (rear - front + maxSize) % maxSize
循環隊列的java實現
package com.victor.queue; import java.util.Scanner; //數組模擬循環隊列 public class CircleArrayQueueDemo { public static void main(String[] args) { CircleQueue cq = new CircleQueue(4); //有效數據3個 char key = ' '; //接收用戶輸入 Scanner scanner = new Scanner(System.in); boolean loop = true; //輸出一個菜單欄 while(loop){ System.out.println("s(show): 打印隊列"); System.out.println("a(add): 入隊列"); System.out.println("g(get): 出隊列"); System.out.println("h(head): 打印隊頭"); System.out.println("e(exit): 退出程序"); key = scanner.next().charAt(0); switch (key) { case 's': cq.showQueue(); break; case 'a': //入隊列 try { System.out.println("請輸入一個整數"); int value = scanner.nextInt(); cq.addQueue(value); //最好判斷一下value是否是整數 } catch (Exception e) { // TODO: handle exception System.out.println(e.getMessage()); } break; case 'g': //出隊列 try { int res = cq.getQueue(); System.out.printf("出隊列的整數爲%d\n", res); } catch (Exception e) { // TODO: handle exception System.out.println(e.getMessage()); //輸出getQueue()方法中定義好的異常信息 } break; case 'h': //打印隊頭 try { int res = cq.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("程序退出"); } } //使用數組模擬循環隊列,CircleQueue類 class CircleQueue{ private int maxSize; //數組的最大容量 private int front; //隊列頭 private int rear; //隊列尾,指向隊列尾部後一個元素的位置 private int[] arr; //該數組用於存放數據,模擬隊列 //隊列的構造方法 public CircleQueue(int arrMaxSize){ maxSize = arrMaxSize; arr = new int[maxSize]; front = 0; //隊列頭部 rear = 0; //隊列尾部,指向隊列尾部後一個元素的位置,front=rear時隊列爲空 } //判斷隊列是否爲滿隊列,由於預留了一個空間,因此要rear+1 public boolean isFull(){ return front == (rear + 1) % maxSize; } //判斷隊列是否爲空隊列,跟簡單隊列的條件同樣 public boolean isEmpty(){ return rear == front; } //入隊列 public void addQueue(int n){ if(isFull()){ throw new RuntimeException("隊列滿,不能添加數據了"); } arr[rear] = n; rear = (rear + 1) % maxSize; //rear要循環 } //出隊列 public int getQueue(){ if(isEmpty()){ //拋出異常 throw new RuntimeException("隊列空,不能出隊列了"); } int value = arr[front]; front = (front + 1) % maxSize; //front要循環 return value; } //打印隊列 public void showQueue(){ if(isEmpty()){ System.out.println("隊列空"); return; } // 打印隊列中的有效元素,注意這裏i的邊界條件,size()方法見下面 for (int i = front; i < front + size(); i++){ int index = i % maxSize; //index爲循環後的下標 System.out.printf("arr[%d]=%d\n",index, arr[index]); //格式化輸出 } } //打印隊頭,不是出隊列 public int headQueue(){ if (isEmpty()){ //拋出異常 throw new RuntimeException("隊列空,不能打印頭"); } return arr[front]; } //求出當前隊列的有效數據個數 public int size(){ return (rear - front + maxSize) % maxSize; } }
reference
韓順平數據結構
大話數據結構