假想的環 充分利用空間,當rear=4,下一步到位置0
元素進隊,影響的是隊尾的值
進隊才能隊滿 rear+1 % 最大值 是否等於隊頭
上一節中關於隊列存在一個問題,隊列是一次性隊列,其實也是數組只用了一次,無法再次往隊列中添加數據,這是數組實現隊列的bug,所以在這一節會解決這個bug,采用環形隊列的形式解決。
環形隊列的思路如下
front:表示隊列的第一個元素的位置,front初始值默認為0
rear:表示隊列的最后一個元素的后一個位置,rear初始值默認為0,因為需要空出一個空間作為“約定”
當隊列滿時,條件是(rear + 1) % maxSize == front
當隊列為空,條件是rear = front
當這樣分析后,隊列中有效的數據個數為(rear + maxSize - front) % maxSize
數組實現環形隊列是數據結構的第一個難度,首先需要聲明數組實現環形隊列的方法有很多,但是這種是我個人覺得比較好理解的一種,這里做一下總結:front指針表示隊首,並且控制出隊;rear指針表示隊尾的后一個位置,並且表示入隊;隊列長度為L時,隊列可以存儲的有效數據為L-1,因為空出一個空間作為約定,並且這個空間在不斷的變化。
這里解釋一下上面這張圖:初始化隊列的時候,隊列的空間為4,隊首指針front=0,隊尾指針rear=0;把10入隊,入隊的時候front不動,將rear后移,即rear=(rear+1)%maxsize;當rear等於front時,表示隊列滿了。出隊的時候rear不動,front后移,即front = (front+1)%maxsize;
環形隊列就可以將隊列無限次使用。
二、環形隊列的代碼實現
這里總結一下,環形隊列並不是在內存中是向一個手環一樣存儲的,實際上你使用數組實現,在內存中就是一個普通的數組,這個數組長度是固定的,但是通過兩個指針front和rear,取余的方式將這個隊列變成了環形隊列,而不像上一節說的那樣的一個一次性的隊列,環形隊列的有點更加多,比如可以充分利用元素空間,其次出隊速度和入隊速度都非常快。
使用取余的方式做環形隊列是需要注意一點,就是如果隊列的長度為5的話,那么隊列最多可以存儲4個元素,因為需要空出一個空間來作為取余的約定,這個用文字表達起來很麻煩,只要按照這篇文章首部的圖片所示,自己在草稿紙上畫一個這樣的示意圖,那么對於環形隊列的理解就非常深刻了。
這里說一句題外話,環形隊列是數據結構與算法中第一個難點,前面的稀疏數組和隊列都是比較簡單的,但是環形隊列是比較難理解的,后面還有更加難的單向環形鏈表等等,要堅持下去,我也會堅持下去盡量用好理解的白話講述數據結構與算法的。
------------------------------------------------------------------------------------------------------------------------------------
預留一個空間判斷是否為滿還是空 front為0
假設(0+3+0)%3 = 0 個有效數字
class CircleArray{
//編寫一個類,用數組模擬
private int maxSize;//表示數組最大容量
private int front;//隊列的第一個元素
private int rear;//指向隊列的最后一個元素的后一個位置,因為要空一格位置
private int[] arr;//該數組用於存放數據 模擬隊列
public CircleArray(int arrmaxSize){
maxSize = arrmaxSize;
arr = new int[maxSize];
}
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;
} //將rear后移 必須考慮取模防止越界
arr[rear]= n;
rear = (rear+1)%maxSize;
}
public int getQueue(){
if (isEmpty()) {
throw new RuntimeException("空");
}
//分析出front是指向隊列的第一個元素
//1.先將front對應的值保留到一個臨時變量
//2.將front后移
//3.將臨時保存的變量返回
int value = arr[front];
//arr[front] = arr[front++];肯定會報數組越界
front = (front + 1 )%maxSize;
return value;
}
public void showQueue(){
if (isEmpty()) {
System.out.println("為空");
}
//思路:從front開始遍歷 遍歷多少個元素 3+4-1就是例子 當前隊列的有效個數
for (int i = front; i < front+size(); i++) {
System.out.printf("arr[%d]=%d\n",i%maxSize,arr[i%maxSize]);//有可能超過數組大小
}
}
public int size(){
return (rear+maxSize-front)%maxSize;
}
public int showhead(){
if (isEmpty()) {
throw new RuntimeException("隊列空的沒有數據");
}
return arr[front];//本身就指向第一個元素
}
約定的空間為0 ,動態變化
再添加的話會加到a[3]的位置