隊列
- 隊列是一個有序列表,遵循先入先出的原則;先存入隊列的數據,要先取出(出列)。後存入的要後取出(入列)。隊列特性簡述爲First-In-First-Out(FIFO)。
- 隊列結構可以來解決在排隊情形下的問題,但不要僅侷限於排隊系統之類的問題。在一些算法中能靈活地運用到隊列結構,其關鍵因素是其特性,FIFO。
- 隊列可以用數組或是鏈表來實現,數組實現更加具有難度,而且比較有代表性。這篇博客我們將介紹如何使用數組實現隊列。
- 圖示隊列是用數組實現的:
- 隊列容量爲MaxSize 。
- 隊列的頭部由front記錄,front指向頭部元素的前一個位置;rear記錄隊列尾部,rear指向尾部元素。front和rear是數組的下標。(注意,這裏非常重要也比較容易混淆,front不是指向頭部元素,而rear是指向尾部元素)。
- 當元素入列時,rear數值加1;元素出列時,front數值加1。
- 這裏顯然,該隊列有一個缺陷:當有MaxSize數量的元素出列時或rear爲MaxSize - 1時,無法再有元素可以入列。那麼這就是一個一次性隊列,實際應用不是很大。
環形隊列
前面我們瞭解到"一次性"數組的侷限性。現在我們來改造一下數組,通過取模運算把數組想象成一個環狀的數據順序存儲結構。
- 在改造之前我們來做一些規定,這些規定與前面隊列的規定有些區別,需要注意:
- front指向數組的第一個元素,front初始值爲0;rear指向最後元素的後一個位置,初始值爲0(因爲環狀的特點,最後元素的後一個位置爲0)。
- 數組可以儲存MaxSize個元素。
- 根據規定我們可以得出幾個結論:
- 當(rear + 1)% MaxSize == front時隊列滿。
- 當rear == front隊列空。
- 代碼實現:
public class CircleQueue {
private int MaxSize;
private int [] array;
private int front;
private int rear;
public CircleQueue(int MaxSize){
this.MaxSize = MaxSize;
this.array = new int [MaxSize];
front = 0;
rear = 0;
}
/**
* Judge if the array is empty.
* @return, a boolean value
*/
public boolean isEmpty(){
return this.front == this.rear;
}
/**
* Judge if the array is full.
* @return, a boolean value
*/
public boolean isFull(){
return (this.rear + 1) % this.MaxSize == this.front;
}
/**
* Make a new element queue in.
* @param element, new element which queue in to the array.
*/
public void queueIn(int element){
if(!isFull()){
//把當前入列元素放入rear位置
this.array[this.front] = element;
return;
}
//rear向後移動一個位置,這裏的取模運算是防止溢出,也是達到循環效果。
this.rear = (this.rear + 1) % this.MaxSize;
}
/**
* Make the front element queue out.
* @return, the front element
*/
public int queueOut() throws Exception {
if(isEmpty()){
throw new Exception("The array is empty!");
}
int temp = this.array[this.front];
this.front = (this.front + 1) % this.MaxSize;
return temp;
}
/**
* Get a number indicating the elements in array.
* @return, int value
*/
public int getElementNumber(){
//這裏的加MaxSize的處理還考慮到了實際數組中rear再front前面
return (this.rear - this.front + this.MaxSize) % this.MaxSize;
}
/**
* print out all elements in array according to the order.
*/
public void printArray(){
//注意,從front開始打印,數組中元素個數控制打印次數,i求餘防止溢出。
for(int i = this.front; i < this.front + getElementNumber();i ++){
System.out.print(this.array[(i % this.MaxSize)] + " ");
}
}
/**
* peek the front element.
* @return, the front element.
* @throws Exception, throw exception if the array is empty.
*/
public int peek() throws Exception {
if(!isEmpty()){
throw new Exception("The array is empty!");
}
return this.array[this.front];
}
}
- 注意,實現代碼的過程中已經把注意事項和關鍵步驟寫明,環形隊列的邊界條件要仔細想明白。根據其定義和規定來實現代碼,並不難。如果想使用該隊列儲存其他類型元素(更具有實際意義),使用泛型知識改造即可,後面我們會講到該知識。