天天看點

什麼是隊列,隊列的java數組實作

一、什麼是隊列?

隊列是資料從表的一端進,另一端出,并遵循“先進先出” 原則的線性存儲結構。

什麼是隊列,隊列的java數組實作

圖一(隊列存儲結構)

通常,稱進資料的一端為 “隊尾”,出資料的一端為 “隊頭”,資料元素進隊列的過程稱為 “入隊”,出隊列的過程稱為 “出隊”。

不僅如此,隊列中資料的進出要遵循 “先進先出” 的原則,即最先進隊列的資料元素,同樣要最先出隊列。拿圖 1 中的隊列來說,從資料在隊列中的存儲狀态可以分析出,元素 1 最先進隊,其次是元素 2,最後是元素 3。此時如果将元素 3 出隊,根據隊列 “先進先出” 的特點,元素 1 要先出隊列,元素 2 再出隊列,最後才輪到元素 3 出隊列。

棧和隊列不要混淆,棧結構是一端封口,特點是"先進後出";而隊列的兩端全是開口,特點是"先進先出"。

二、隊列存儲實作

隊列存儲結構的實作有以下兩種方式:

1.順序隊列:在順序表的基礎上實作的隊列結構;

2.鍊隊列:在連結清單的基礎上實作的隊列結構;

(本文主要将順序存儲)

三、順序隊列簡單實作

由于順序隊列的底層使用的是數組,是以需預先申請一塊足夠大的記憶體空間初始化順序隊列。除此之外,為了滿足順序隊列中資料從隊尾進,隊頭出且先進先出的要求,我們還需要定義兩個指針(top 和 rear)分别用于指向順序隊列中的隊頭元素和隊尾元素,如圖 1 所示:

什麼是隊列,隊列的java數組實作

圖 1 順序隊列實作示意圖

由于順序隊列初始狀态沒有存儲任何元素,是以 top 指針和 rear 指針重合,且由于順序隊列底層實作靠的是數組,是以 top 和 rear 實際上是兩個變量,它的值分别是隊頭元素和隊尾元素所在數組位置的下标。

在圖 1 的基礎上,當有資料元素進隊列時,對應的實作操作是将其存儲在指針 rear 指向的數組位置,然後 rear+1;當需要隊頭元素出隊時,僅需做 top+1 操作。

例如,在圖 1 基礎上将 {1,2,3,4} 用順序隊列存儲的實作操作如圖 2 所示:

什麼是隊列,隊列的java數組實作

圖二 資料進順序隊列的過程實作示意圖

在圖 2 基礎上,順序隊列中資料出隊列的實作過程如圖 3 所示:

什麼是隊列,隊列的java數組實作

圖三 資料出順序隊列的過程示意圖

從以上我們可以大緻知道,入隊列時rear也就是隊尾會向後移,出隊列時top也就是隊頭向後移,當它們重合的時候,也就是隊列元素為空的時候。

四、JAVA自帶隊列類的使用

public class Team {
	/*聲明一個queue對象,
	    * ArrayBlockingQueue :一個由數組支援的有界隊列。
	  * LinkedBlockingQueue :一個由連結節點支援的可選有界隊列。
	  * PriorityBlockingQueue :一個由優先級堆支援的無界優先級隊列。
	  * DelayQueue :一個由優先級堆支援的、基于時間的排程隊列。
	  * SynchronousQueue :一個利用 BlockingQueue 接口的簡單聚集(rendezvous)機制。*/
	Queue queue=new ArrayBlockingQueue(20);  
	public Team(){
		//入隊
		queue.add(1);
		queue.add(2);
		queue.add(3);
		//出隊
		queue.poll();
		System.out.println(queue);
	}
	public static void main(String[] args) {
		new Team();
	}
}

           

結果如圖:

什麼是隊列,隊列的java數組實作

其中隊列操作方法:

add 增加一個元索 如果隊列已滿,則抛出一個IIIegaISlabEepeplian異常

  remove 移除并傳回隊列頭部的元素 如果隊列為空,則抛出一個NoSuchElementException異常

  element 傳回隊列頭部的元素 如果隊列為空,則抛出一個NoSuchElementException異常

  offer 添加一個元素并傳回true 如果隊列已滿,則傳回false

  poll 移除并返問隊列頭部的元素 如果隊列為空,則傳回null

  peek 傳回隊列頭部的元素 如果隊列為空,則傳回null

  put 添加一個元素 如果隊列滿,則阻塞

  take 移除并傳回隊列頭部的元素 如果隊列為空,則阻塞

添加删除時盡量使用offer,poll,用add和remove失敗抛異常

五、JAVA代碼實作隊列

package ddd;

public class Tesr {
	//因為如圖中,隊列剛開始指向0是以此處給它們兩賦初值為0,正好也對應數組下标
	int rear=0;
	int top=0;
	//數組
	int arr[];
	//隊列的長度
	int size;
	
	//給數組隊列賦容量
		public void numArr(int num){
			this.size=num;
			arr=new int[num];
		}
		
	//判斷隊列是否為空
		public boolean isEmpty(){
			return rear==top;
		}
		
	//判斷隊列是否已滿
		public boolean isFull(){
			return rear==size-1;
		}
		//入隊
	public void add(int value){
		if(isFull()){
			throw new RuntimeException("隊列已滿");
		}
		rear++;
		arr[rear-1]=value;
		System.out.println("存入的值為:"+value);
	}
	//出隊
	public void poll(){
		if(isEmpty()){
			throw new RuntimeException("隊列已空");
		}
	 	top++;
	 	//top++之後指向下一個元素,取出的元素是++之前的元素,是以top-1
	 	System.out.println("取出的值為:"+arr[top-1]);
	}
	
	//周遊隊列
	public void see(){
		if(isEmpty()){
			return ;
		}
		for (int i = 0; i <=rear-1; i++) {
			System.out.println(arr[i]);
		}
	}
	public static void main(String[] args) {
		Tesr test=new Tesr();
		test.numArr(20);
		test.add(1);
		test.add(2);
		test.add(3);
		test.poll();
		test.poll();
		test.poll();
		test.poll();
		test.see();
	}
}

           

測試結果如圖:

什麼是隊列,隊列的java數組實作

以上是基于單向連結清單實作的,缺點在于:

指針 top 和 rear 重合位置指向了後續的重合點而不再是 a[0]。也就是說,整個順序隊列在資料不斷地進隊出隊過程中,在順序表中的位置不斷後移。

順序隊列整體後移造成的影響是:

  • 順序隊列之前的數組存儲空間将無法再被使用,造成了空間浪費;
  • 如果順序表申請的空間不足夠大,則直接造成程式中數組 a 溢出,産生溢出錯誤;

為了解決以上兩個問題,可以使用巧妙的方法将順序表打造成一個環狀表,如下圖所示:

什麼是隊列,隊列的java數組實作

隻是一個想象圖,在真正的實作時,沒必要真建立這樣一種結構,我們還是使用之前的順序表,也還是使用之前的程式,隻需要對其進行一點小小的改變:(具體改變下次更)

如有不足請指出