1. 程式人生 > >Java成神之路:第三帖----資料結構與演算法之佇列

Java成神之路:第三帖----資料結構與演算法之佇列

[toc] # 資料結構與演算法--佇列 ***今天掉了兩根頭髮,摸掉的,記得 別亂摸,很珍貴的!!*** ## 什麼是佇列? 1)佇列是一個有序列表,可以用陣列或是連結串列來實現 2)遵循 ***先入先出*** 的原則。即:先存入佇列的資料,要先取出。後存入的要後取出 3)示意圖:(使用陣列模擬佇列示意圖) ![佇列](http://tc.glulu7.cn/20200915174131.png) **rear表示的是佇列尾,front表示的是佇列首,front值等於-1,表示佇列資料首的前一位(用陣列模擬佇列,陣列的下標第一個為0,用-1表示資料首的前一位),rear的值為-1,在這裡我認為是為了和front保持一致,這樣```rear == front```,表示陣列為空!** *** ## 用陣列模擬佇列的思路 **佇列本身是有序列表,若使用陣列的結構來儲存佇列的資料,則佇列陣列的宣告如下圖,其中 max Size是該佇列的最大容量,因為佇列的輸出、輸入是分別從前後端來處理,因此需要兩個變數 front及rear分別記錄佇列前後端的下標,front會隨著資料輸出而改變,而rear則是隨著資料輸入而改變,還是這個圖嘻嘻~** ![佇列](http://tc.glulu7.cn/20200915174131.png) ** 當我們將資料存入佇列時稱為”addQueue”,addQueue的處理需要有兩個步驟: 1. 將尾指標往後移:```rear+1```,當``` front == rear``` 隊列表示為空 (PS:陣列頭和陣列尾在一起,能不空嗎) 2. 若尾指標rear小於佇列的最大下標 maxSize-1,則將資料存入rear所指的陣列元素中,否則無法存入資料```reaI == maxSize-1 ``` 此時表示佇列滿 3. 話不多說,上程式碼:** ``` package com.yishuai.queue; public class ArrayQueueDemo { public static void main(String[] args) { //資料測試 ArrayQueue arrayQueue = new ArrayQueue(3); } } class ArrayQueue { private int maxSize;//最大容量 private int front;//佇列頭 private int rear;//佇列尾 private int[] arr;//存放資料的陣列,模擬佇列 //佇列初始化 public ArrayQueue(int maxSize) { this.maxSize = maxSize; 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 data) { //如果佇列已經滿了,就不能再新增資料進入 if (isFull()) { System.out.println("佇列已經滿了"); return; } rear++; //資料增加,佇列尾的下標增加,佇列頭不變 arr[rear] = data; } //將資料從佇列中取出 public int getQueue() { if (isEmpty()) { throw new RuntimeException("佇列為空,沒有資料可取"); } front++; return arr[front]; } //展示出佇列中的所有資料 public void showQueue() { if (isEmpty()) { System.out.println("佇列為空,沒有資料哦~"); } for (int data : arr) { System.out.print(data + "\t"); } } } ``` ## 新的問題 **因為此時的佇列,採取的是一個鏈式的,也就意味著,當前面的資料被取出的時候,即使此時佇列已經不是滿的了,但是佇列尾還是和maxSize - 1一樣大,資料在插入的時候,仍然還是會顯示:佇列已經滿啦~,此時我們如果想要解決這個問題,我們要使用:** ***環形佇列*** ## 迴圈佇列 有兩種方法(坑了我幾個小時): ### 第一種: **宣告:font為頭部第一個資料,rear為尾部最後一個數據的下一個位置** 1. 當```font == rear```的時候,佇列為空(這個沒問題吧?) 2. 初始:```font == rear == 0```,此時佇列為空,當資料進入的時候,rear開始往後走,也就是+1 3. 假如```maxSize=5```,放入四個資料,也就是rear往後走了四步之後,```rear=4```了,陣列有五個位置,但是裡面只有四個資料,最後一個空的資料還沒有放入,此時,假如rear再往前走一步,```rear=5```,但是陣列的下標是從0開始的,也就是說,(0,1,2,3,4)這裡就是五個單元格,到頂了 4. 所以```rea```r到5的時候,只能往回走,也就是說,```rear=4```之後,不是```rear=5```,而是```rear=0```,此時font也等於0,```font == rear```了,刺激吧? 5. 前面說```font == rear```時,佇列為空,但是現在說```font == rear```時,佇列又是為滿的,哪裡出錯了嗎?大部分人是不是和我一樣的思想(也可能是我自戀),你沒錯,兩個都是對的,所以呢,單純的依靠font和rear已經不能滿足判斷的條件了,我的方法是再加入一個count計數,從0開始,加一個數據,```count++```,取一個數據,```count--``` 。count會在【0,5】之間變動,當```font == rear```且```count=0```時,佇列為空,當```font == rear```且```count=5```時,佇列為滿,至於有效資料的個數,直接看count的值即可,這是第一種方法(我感覺比第二種好)!! ### 第二種(我和室友討論了一個多小時,吐槽吐槽) ***PS:重點來了!!!*** **這種方法有一個單元格是空的!!!假如最大空間為5,只能放入4個數據,還有一個空間,留著種水稻(粗口不斷!),竟然不把空間用完,這也太浪費了,我看了3遍,想著應該不會這麼傻吧,空間都不用完,家裡有礦啊,還以為是自己哪裡沒弄懂,搞了一遍又一遍,和室友討論了很久,也沒得出結論,最後翻書解決了(不賣書,別私聊找我問哈),重複一遍,有一個空間是空的!!一直都是!!** **這種方法,意思是: 宣告:font為頭部第一個資料,rear為尾部最後一個數據的下一個位置** 1. 當```font == rear```的時候,佇列為空(這個沒問題吧?沒問題吧?) 2. 假如```maxSize = 5```,什麼時候滿了呢?當rear跑到4的時候就滿了,也就是```rear == 4```,裡面就四個資料,還有一個空間呢,重複:種水稻了(空的),所以```(rear+1)% maxSize == font```時,就滿了(%是取餘數,也叫取模,/是取商),rear+1什麼意思?補上種水稻的那個空,然後再對maxSize取模,為什麼取模?因為可能正好是和font同一圈,也有可能已經和font相差一圈了,所以要做取模操作。 3. 那麼有多少有效資料呢?可以直接看佇列的長度,也就是 |rear-font|(取絕對值,問我為什麼的先去面壁,再評論我給你回覆),所以就可以寫成這樣```(rear+maxSize-font)%maxSize```, ***更新結束了,我頭髮又掉了兩根,啊啊啊!!!*** 不點個贊再走,你對得起我頭髮嗎,對得