1. 隊列的介紹
- 隊列是一個有序列表,可以用數組或是鏈表來實現。
- 遵循先入先出的原則。即:先存入隊列的數據,要先取出。后存入的要后取出
- 示意圖:(使用數組模擬隊列示意圖)
2. 數組模擬隊列的思路
- 隊列本身提有序列表,若使用數組的結構來存儲隊列的數據,則隊列數組的聲明如下圖,其中 maxSize是該隊列的最大容量。
- ·因為隊列的輸出、輸入是分別從前后端來處理,因此需要兩個變量front 及 rear分別記錄隊列前后端的下標,front會隨着數據輸出而改變,而rear則是隨着數據輸入而改變。
- 當我們將數據存入隊列時稱為”addQueue”, addQueue 的處理需要有兩個步驟:思路分析
- 將尾指針往后移: rear+1 ,當front == rear【空】
- 若尾指針 rear 小於隊列的最大下標 maxSize-1,則將數據存入rear所指的數組元素中,否則無法存入數據。rear == maxSize - 1 [隊列滿]
3. 普通隊列實現的參考代碼
注:下述代碼front默認初始值為 -1 ,rear 的默認初始值為 -1
package datastructureexamples;
import java.util.Scanner;
public class arrayQueueDemo {
public static void main(String[] args) {
//測試
//創建一個隊列
arrayQueue queue = 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':
queue.showQueue();
break;
case 'a':
System.out.println("輸出一個數");
int value = scanner.nextInt();
queue.addQueue(value);
break;
case 'g'://取出數據
try{
int res = queue.getQueue();
System.out.printf("取出的數據是%d\n",res);
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
case 'h'://查看隊列頭的數據
try{
int res = queue.headQueue();
System.out.printf("隊列頭的數據是%d\n",res);
}catch(Exception e){
System.out.println("e.getMessage()");
}
break;
case 'e'://退出
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出~~");
// TODO Auto-generated method stub
}
}
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;//指向隊列頭部,分析出front是指向隊列頭部的前一個位置
rear = -1;//指向隊列尾,指向隊列尾的數據(即就是隊列最后一個數據)
}
//判斷隊列是否為滿
public boolean isFull(){
return rear == maxSize - 1;
}
//判斷隊列是否為空
public boolean isEmpty(){
return rear == front;
}
//添加數據到隊列
public void addQueue(int n){
//判斷隊列是否滿
if(isFull()){
System.out.println("隊列滿,不能加人數據-");
return;
}
rear++;//讓rear后移
arr[rear] = n;
}
//獲取隊列的數據,出隊列
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 headQueue(){
//判斷
if(isEmpty()){
throw new RuntimeException("隊列是空的,沒有數據");
}
return arr[front + 1];
}
}
輸出結果:
隊列空的,沒有數據
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列中取出數據
h(head):查看隊列頭的數據
h
e.getMessage()
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列中取出數據
h(head):查看隊列頭的數據
g
隊列空,不能取數據
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列中取出數據
h(head):查看隊列頭的數據
注:上述用數組去模擬隊列的方法有一個缺陷,即內存只開辟了一次,數據只能存儲一次,當全部取出數據之后,不能添加新的數據到已經空余的內存空間中。因此需要設置一種新的隊列的實現方式來改變上述隊列的弊端。
4. 數組模擬循環隊列
-
對前面的數組模擬隊列的優化,充分利用數組.因此將數組看做是一個環形的。(通過取模的方式來實現即可)
-
分析說明:
- 尾索引的下一個為頭索引時表示隊列滿,即將隊列容量空出一個作為約定,這個在做判斷隊列滿的時候需要注意 (rear + 1) % maxSize == front [滿]
- rear == front [空]
- 分析示意圖:
思路如下:
-
front變量的含義做一個調整:
front就指向隊列的第一個元素,也就是說 arr[front] 就是隊列的第一個元素 front 的初始值 = 0 -
rear變量的含義做一個調整:
rear指向隊列的最后一個元素的后一個位置.因為希望空出一個空間做為約定.rear的初始值=0 -
當隊列滿時,條件是 (rear +1) % maxSize = front【滿】
-
對隊列為空的條件,rear== front [空]
-
當我們這樣分析,隊列中有效的數據的個數 (rear+ maxSize - front) % maxSize // rear=1 front=0
-
我們就可以在原來的隊列上修改得到,一個環形隊列
5. 循環隊列實現的參考代碼
package datastructureexamples;
import java.util.Scanner;
public class CircleArraryQueueDemo {
public static void main(String[] args) {
//測試
System.out.println("測試數組模擬環形隊列的案例~~");
//創建一個環形隊列
CircleArray queue = new CircleArray(4);//說明設置4,其隊列的有效數據最大是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':
queue.showQueue();
break;
case 'a':
System.out.println("輸出一個數");
int value = scanner.nextInt();
queue.addQueue(value);
break;
case 'g'://取出數據
try{
int res = queue.getQueue();
System.out.printf("取出的數據是%d\n",res);
}catch(Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try{
int res = queue.headQueue();
System.out.printf("隊列頭的數據是%d\n",res);
}catch(Exception e){
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 的初始值=О
private int front; //隊列頭
//rear變量的含義做一個調整:rear 指向隊列的最后一個元素的后一個位置.因為希望空出一個空間做為約定
//rear的初始值=0
private int rear; //隊列尾
private int[] arr; //該數組用於存放數據,模擬隊列
public CircleArray(int arrmaxsize){
maxSize = arrmaxsize;
arr = new int[maxSize];
//front = 0;//注:此處front和rear的初始值設置可以省略,front和rear的默認初始值為零
//rear = 0;
}
//判斷隊列是否為滿
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(){
//rear = 2
// front = 1
// maxSize = 3
return (rear + maxSize - front) % maxSize;
}
//顯示隊列的頭數據,注意不是取出數據
public int headQueue(){
//判斷
if(isEmpty()){
throw new RuntimeException("隊列空的,沒有數據~~");
}
return arr[front];
}
}
輸出結果:
測試數組模擬環形隊列的案例~~
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
s
隊列空的,沒有數據~~
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
a
輸出一個數
10
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
20
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
a
輸出一個數
20
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
a
輸出一個數
30
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
a
輸出一個數
40
隊列滿,不能加入數據--
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
g
取出的數據是10
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
s
arr[1]=20
arr[2]=30
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
s
arr[1]=20
arr[2]=30
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
a
輸出一個數
40
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
a
輸出一個數
50
隊列滿,不能加入數據--
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
h
隊列頭的數據是20
s(show):顯示隊列
e(exit):退出程序
a(add):添加數據到隊列
g(get):從隊列取出數據
h(head):查看隊列頭的數據
.