數據結構與算法(Java)——隊列



1. 隊列的介紹

  1. 隊列是一個有序列表,可以用數組或是鏈表來實現。
  2. 遵循先入先出的原則。即:先存入隊列的數據,要先取出。后存入的要后取出
  3. 示意圖:(使用數組模擬隊列示意圖)
    在這里插入圖片描述

2. 數組模擬隊列的思路

  • 隊列本身提有序列表,若使用數組的結構來存儲隊列的數據,則隊列數組的聲明如下圖,其中 maxSize是該隊列的最大容量。
  • ·因為隊列的輸出、輸入是分別從前后端來處理,因此需要兩個變量front 及 rear分別記錄隊列前后端的下標,front會隨着數據輸出而改變,而rear則是隨着數據輸入而改變。
  • 當我們將數據存入隊列時稱為”addQueue”, addQueue 的處理需要有兩個步驟:思路分析
  1. 將尾指針往后移: rear+1 ,當front == rear【空】
  2. 若尾指針 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. 數組模擬循環隊列

  • 對前面的數組模擬隊列的優化,充分利用數組.因此將數組看做是一個環形的。(通過取模的方式來實現即可)

  • 分析說明:

  1. 尾索引的下一個為頭索引時表示隊列滿,即將隊列容量空出一個作為約定,這個在做判斷隊列滿的時候需要注意 (rear + 1) % maxSize == front [滿]
  2. rear == front [空]
  3. 分析示意圖:

在這里插入圖片描述


思路如下:

  1. front變量的含義做一個調整:
    front就指向隊列的第一個元素,也就是說 arr[front] 就是隊列的第一個元素 front 的初始值 = 0

  2. rear變量的含義做一個調整:
    rear指向隊列的最后一個元素的后一個位置.因為希望空出一個空間做為約定.rear的初始值=0

  3. 當隊列滿時,條件是 (rear +1) % maxSize = front【滿】

  4. 對隊列為空的條件,rear== front [空]

  5. 當我們這樣分析,隊列中有效的數據的個數 (rear+ maxSize - front) % maxSize // rear=1 front=0

  6. 我們就可以在原來的隊列上修改得到,一個環形隊列


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):查看隊列頭的數據

.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM