你們好,我是阿濠,今篇內容跟你們分享的是數據結構之隊列,很高興分享到segmentfault與你們一塊兒學習交流,初次見面請你們多多關照,一塊兒學習進步.
官方定義:隊列(quene)是容許在一端進行插入操做,而在另外一端進行刪除操做的線性表
1.隊列是一個有序列表,能夠用數組或是鏈表
來實現。
2.遵循先入先出
的原則。即:先存入隊列的數據,要先取出。後存入的要後取出算法
好比春運時的標語排隊走得了、走的及時、走得安全、走的溫馨segmentfault
優先排隊的人, 優先處理. (買票, 結帳, WC) 後端
對於棧來講,只須要一個棧頂指針就能夠了。
可是對於隊列來說,須要兩個指針:一個是head指針,指向隊頭,一個tail指針,指向隊尾。數組
這裏圖中初始化無數據的時候隊首和隊尾都爲-1,
當有數據增長的時候,隊尾在變化,而隊首沒有變化,說明是隊首添加數據安全
當有數據取出的時候,隊首在變化,而隊尾沒有變化,說明是隊尾去除數據數據結構
➢隊列自己是有序列表
,若使用數組的結構來存儲隊列的數據
,則隊列數組的聲明以下圖,其中maxSize是該隊列的最大容量。學習
➢由於隊列的輸出、輸入是分別從先後端來處理,所以須要兩個變量front及rear分別記錄隊列先後端的下標
測試
使用front記錄隊首、使用rear記錄隊尾優化
front 會隨着數據輸出
而改變表明取出數據
,而rear則是隨着數據輸入
而改變表明添加數據
spa
如圖所示:
當咱們將數據存入隊列時稱爲"addQueue"
,思路分析以下:
1.判斷隊列是否滿或是否爲空,而後纔將隊尾指針rear日後移:rear+1
2.隊尾指針rear小於數組長度-1能夠添加,若隊尾指針rear==maxSize-1則表明隊列已滿
編寫代碼以下:
//使用數組模擬隊列-編寫ArrayQueue類 public 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; //指向隊列頭部,即返回即第一個數據的前一個位置 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 ; } //後移並添加數據 arr[++rear]=n; } //從隊列取出數據 public int getQueue(){ if(isEmpty()){ throw new RuntimeException("隊列爲空,不能取出數據"); //無需在return 由於throw有帶return } //取出數據後,隊頭須要日後移,而後返回數據 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 showheadQueue(){ //判斷隊列是否爲空 if (isEmpty()) { throw new RuntimeException("隊列爲空,沒有數據"); } return arr[front+1]; } }
如今添加數據完成方法測試看看隊列
//建立一個隊列 ArrayQueue arrayQueue = new ArrayQueue(3); System.out.println("打印隊列數據----------------"); arrayQueue.showQueue();//打印隊列數據 System.out.println("\n添加數據:10"); arrayQueue.addQueue(10);//添加一個數據10 System.out.println("\n打印隊列數據----------------"); arrayQueue.showQueue();//打印隊列數據 //打印頭部數據 System.out.println("\n\n顯示隊列隊首信息:"+arrayQueue.showheadQueue()); 運行結果以下: 打印隊列數據---------------- 隊列爲空,沒法打印數據 添加數據:10 打印隊列數據---------------- arr[0]=10 arr[1]=0 arr[2]=0 顯示隊列隊首信息:10
如今數據添加成功、打印數據添加成功、輸出隊首數據成功,那麼繼續添加數據看看
System.out.println("\n添加數據:20"); arrayQueue.addQueue(20);//添加一個數據10 System.out.println("\n添加數據:30"); arrayQueue.addQueue(30);//添加一個數據10 System.out.println("\n添加數據:40"); arrayQueue.addQueue(40);//添加一個數據10
那麼打印看看會是什麼結果呢?
添加數據:20 添加數據:30 添加數據:40 隊列已滿,沒法添加數據
咱們發現隊列空間爲三,再次添加第四個數據的時候,就會出現隊列已滿沒法添加數據的異常
那麼咱們這樣使用數組模擬隊列,有沒有問題呢?
答案是有的,即數據取出後指向隊首的指針上去了,雖然以前的空間沒有數據了但沒法再次使用了。再次添加數據的時候顯示隊列已滿
1.目前數組使用一次就不能再次使用
,沒有達到複用
的效果
2.將數組使用算法,改爲環形數組模擬環形隊列,使用%
如何將數組轉換成模擬循環隊列呢?
思路分析以下:
1.front指針做用進行調整:front指向數組第一個元素,初始值front=0
2.rear指針做用進行調整:rear指向隊列的最後一個元素後一個元素,初始值rear=0
原先rear指向的是最後一個元素,如今指向最後一個元素後一個元素爲空作約定,這樣隊列滿了以後隊首數據front前面元素就爲空了,在前一個元素就是隊列裏的最後一個元素了
3.當隊列滿時,條件是:(rear+1)%maxSize==front
原先線性數組判斷滿的條件爲rear=maxSize-1,沒有考慮複用,即如今是一個環,那麼此時的條件=(rear+1)%maxSize==front
4.當隊列爲空的條件:rear==front
5.隊列中有效的個數:(rear+maxSize-front)%maxSize
編寫代碼以下:
public class CircleArray { private int maxSize; //表示數組的最大容量 //front 就指向隊列的第一個元素,也就是說arr[ front] //front的初始值= 0 private int front; //rear指向隊列的最後一個元素的後一個位置。由於但願空出一個位置作約定區分隊列滿沒滿 //rear的初始值= 0 private int rear; //隊列尾. private int[] arr; //該數據用於存放數據,模擬隊列 public CircleArray(int arrMaxSize) { maxSize = arrMaxSize; arr = new int[maxSize]; } //判斷隊列是否滿 public boolean isFu1l () { return (rear + 1) % maxSize == front; } //判斷隊列是否爲空 public boolean isEmpty(){ return rear==front; } //添加數據到隊列 public void addQueue(int n) { //判斷隊列是否滿 if (isFu1l()) { System.out.println("隊列滿,不能加入數據~"); return; } //由於rear自己指向最後一個元素的後一個位置 //因此直接賦值,在將rear後移 arr[rear] = n; //rear日後移須要% 即便回到前面有空餘的空間位置 //由於環形隊列是一個環,不能像線性數組直接++ 會形成數組越界 rear=(rear+1)%maxSize; //好比說有模擬環形隊列數組長度5分別爲2,6,7,8 //即下標4是rear指向最後一個元素的後一個位置 //若是取出隊列數據2,front=1 那麼目前的隊列數據便是 6,7,8 //這時rear要回到下標0,不能是++等於下標4 ,因此取% 回到0 } //從隊列取出數據 public int getQueue(){ if(isEmpty()){ throw new RuntimeException("隊列爲空,不能取出數據"); //無需在return 由於throw有帶return } //front的含義:指向隊列的第一個元素 //1.先把front對應的值保存到臨時變量 //2.將front後移,指向新的隊列第一個元素,考慮取% //3.將臨時的變量彈出返回 int value=arr[front]; front=(front+1)%maxSize; return value; //好比說有模擬環形隊列數組長度5分別爲2,6,7,8 //若是取出隊列數據2,那麼此時front須要日後移指向新的首數據 //可是front不能++,由於若是++的話,到了最後一個元素是下標3 //彈出後++front=4,再添加數據時,rear=下標0,而front是4會爆出異常因此須要取% } //打印隊列裏的數據 public void showQueue() { //判斷隊列是否爲空 if (isEmpty()) { System.out.println("隊列爲空,沒法打印數據"); return; } //不能像線性數組直接循環打印出數據,由於是數組模擬環形隊列 //思路:從front開始遍歷,遍歷到front+隊列有效個數 //循環隊列從front開始到front+size(),爲何要+front?不能直接小於size()? //由於好比說循環隊:3,5,6 初始化數據front=0 rear=3 //那麼取出數據3 此時front=1 rear=3 這時打印數據若是是直接小於size() //則指打印出1,2 沒法打印出真正個數 for (int i =front; i <front+size(); i++) { //爲何要i%maxSize 由於是環形,好比說3,5,6 初始化數據front=0 rear=3 //此時取出數據3,5,此時front=2 rear=3,即添加數據4,1 此時front=2 rear=1 //若i=2 此時i<5 5=2+(1 + 4 - 2) % 4; //若i不進行i%maxSize 則會在i++時沒法回到環形頭部 會++到front=5 數組越界爆出異常 //因此須要i%maxSize回到環形頭部 System.out.printf("arr[%d]=%d\t", i % maxSize, arr[i % maxSize]); } } //求出當前隊列有效數據的個數 public int size() { //好比說環形隊列空間=4 值=3,5,6 //初始值front=0 rear=4 //此時隊列有效數據(4+3-0)%4=3 表明有效個數=3 return (rear + maxSize - front) % maxSize; } //打印隊列頭部數據 public int showheadQueue(){ //判斷隊列是否爲空 if (isEmpty()) { throw new RuntimeException("隊列爲空,沒有數據"); } //直接返回front,由於front指向隊列第一個元素 return arr[front]; } }
那麼如今讓咱們添加數據測試看看把
//建立一個隊列 CircleArray arrayQueue = new CircleArray(4); System.out.println("\n添加數據:10"); arrayQueue.addQueue(10);//添加一個數據10 System.out.println("\n打印隊列數據----------------"); arrayQueue.showQueue(); 運行結果以下: 添加數據:10 打印隊列數據---------------- arr[0]=10
咱們再加多點數據看看,並看看數組模擬環形隊列有什麼不同?
System.out.println("\n添加數據:10"); arrayQueue.addQueue(10);//添加一個數據10 System.out.println("\n添加數據:20"); arrayQueue.addQueue(20);//添加一個數據20 System.out.println("\n添加數據:30"); arrayQueue.addQueue(30);//添加一個數據30 //打印頭部數據 System.out.println("\n\n顯示隊列隊首信息:"+arrayQueue.showheadQueue()); System.out.println("\n打印隊列數據----------------"); arrayQueue.showQueue(); 運行結果以下: 顯示隊列隊首信息:10 打印隊列數據---------------- arr[0]=10 arr[1]=20 arr[2]=30
此時咱們彈出隊首再看看?
System.out.println("\n取出隊列首----------------"); arrayQueue.getQueue(); System.out.println("\n打印隊列數據----------------"); arrayQueue.showQueue(); 運行結果以下: 取出隊列首---------------- 打印隊列數據---------------- arr[1]=20 arr[2]=30
此時咱們能添加數據嘛?答案是能夠的
它會加到哪呢?答案是:會加到下標3的位置,此時下標0就做爲約定位置,由於這個約定的位置是會動態變化的!!!
System.out.println("\n添加數據:50"); arrayQueue.addQueue(50);//添加一個數據50 System.out.println("\n打印隊列數據----------------"); arrayQueue.showQueue(); 運行結果以下: 添加數據:50 打印隊列數據---------------- arr[1]=20 arr[2]=30 arr[3]=50
那麼此時的數組便可反覆利用,測試完成