Java 單向佇列及環形佇列
佇列的特點
1.可以使用陣列和連結串列兩種方式來實現。
2.遵循先入先出(FIFO)的規則,即先進入的資料先出。
3.屬於有序列表。
圖解實現過程:
1.定義一個固定長度的陣列,長度為maxSize。
2.設定兩個指標first = -1(指向佇列第一個資料的前一位,這樣保證在新增第一 個數據以後頭指標為0,和陣列的下標一樣,且用於操作出隊)和last = -1(指向 隊尾,用於操作入隊)。
3.即first會因為出隊操作而增加,last會因為入隊操作而增加
程式碼實現:
package 佇列; public class ArrayQueueTest { public static void main(String[] args) { ArrayQueue arrayQueue = new ArrayQueue(3); arrayQueue.addQueue("瓊"); arrayQueue.addQueue("贇"); arrayQueue.addQueue("瓏"); arrayQueue.showAllQueueData(); System.out.println(arrayQueue.getQueue()); } } class ArrayQueue{ private int maxSize;//定義佇列的最大長度 private int first ;//指向佇列頭的前一個位置!!前一個位置!!出隊方向 private int last ;//指向佇列尾部!!即最後一個數據!!!入隊方向 private String[] arr; //先建一個空的陣列,具體長度未知,需要maxSize來確定。 //構造器初始化佇列資訊 public ArrayQueue(int maxSize){ this.maxSize = maxSize; this.first = -1; this.last = -1; arr = new String[maxSize]; } //判斷是否為空 public boolean isEmpty(){ if (first == last) { System.out.println("佇列為空~~"); return true; }else { System.out.println("佇列不為空~~"); return false; } } //判斷佇列是否滿 public boolean isFull(){ if (last == maxSize-1) { System.out.println("佇列已滿~~"); return true; }else { System.out.println("佇列未滿~~"); return false; } } //入隊 public void addQueue(String data){ if (last == maxSize-1){ System.out.println("佇列已滿,不能再新增!!"); return; }else { last++; //新增資料只和末尾下標有關 arr[last] = data; return; } } //出隊 public String getQueue(){ if (isEmpty()) { //因為getQueue方法是int型,需要返回資料,如果無資料,也需要返回 //如果返回-1或者其他資料,會讓人誤解獲取到的數就是-1或者其他 //所以用丟擲異常來處理 throw new RuntimeException("佇列為空,無資料~~"); } else { first++; return arr[first]; } } //遍歷佇列所有資訊 public void showAllQueueData(){ if (first == last){ return; } for (int i = 0; i < arr.length; i++) { System.out.println("arr["+i+"]"+"="+arr[i]); } } //獲取佇列頭資料 public String headQueueData(){ if (isEmpty()){ throw new RuntimeException("無資料~~~"); } return arr[++first]; } }
缺點:
由於出隊操作,使得first指標上移變大,導致陣列前面空出來的位置就不能再繼續新增資料,即不能再被重複使用,這樣一個佇列只能使用一次,記憶體效率太低,所以需要使用環形佇列來優化解決。
優化解決——環形佇列實現思路
1.first指標初始預設設定為0,指向佇列頭部,則arr[first] 就是第一個資料。
2.last指標初始預設也為0,但是會隨著增加資料而後移。
3.佇列滿的條件:
(last + 1) % maxSize == first
last+1是為了讓指標後移,而且如果不設定為 last+1 那麼一開始的時候last為0 , last % maxSize == 0,且first也為0,還沒加資料就滿了。
4.佇列為空的條件:
first == last
5.由於判斷是否滿的時候: last+1 ,導致實際上可以裝的資料比陣列長度少 1
環形佇列各步驟及各方法實現講解
1.佇列初始化 :
class CircleArryQueue{ private int maxSize ; //陣列長度,即佇列最大容量 private int first; //頭指標,控制出隊操作 private int last; //尾指標,控制入隊操作 private int[] arr; //陣列型別,可以換其他的。 //構造器初始化資訊 public CircleArryQueue(int maxSize){ this.maxSize = maxSize; this.arr = new int[maxSize]; this.first = 0; //這兩個可以不加,不叫也是預設為0 this.last = 0; } }
2.判斷佇列是否為空:
public boolean isEmpty(){ //頭指標和尾指標一樣 則說明為空 return last == first; }
3.判斷佇列是否滿:
/* *這裡的 last+1 主要是為了讓指標後移,特別是在佇列尾部新增資料的時候,本來用last也可以判斷,但 *是一開始還沒加資料的時候,如果直接用last % maxSize == first,結果是true,所以為了解決指標後*移和判斷是否滿,用來last+1。其次,因為last+1可能會導致陣列指標越界,所以用取模來控制它的範 * 圍,同時保證他會在一個固定的範圍迴圈變換,也利於環形佇列的實現。 */ public boolean isFull(){ return (last + 1) % maxSize == first; }
4.新增資料到佇列尾部:入隊
public void pushData(int data){ //先判斷是否滿了 if(isFull()){ System.out.println("佇列已經滿啦~~"); return; } arr[last] = data; //last+1是為了後移,取模是為了避免指標越界,同時可以讓指標迴圈 last = (last + 1) % maxSize; }
5.取出隊首資料:出隊
public int popData(){ if (isEmpty()) { //拋異常就可以不用返回資料了 new RuntimeException("佇列為空,沒有獲取到資料~~"); } //要先把first對應的陣列資料儲存——>first後移——>返回資料 int value = arr[first]; //first+1的操作和last+1是一樣的,取模也是 first = (first+1) % maxSize; System.out.println(value); return value; //如果不儲存first指標 那麼返回的資料就不對了 //如果直接返回資料,那first指標還沒後移 也不對,所以需要使用第三方變數 }
6.展示佇列中所有資料:
public void showAllData(){ if (isEmpty()) { System.out.println("佇列為空,沒有資料~~"); return; } //此處i不為0,是因為有可能之前有過popData()操作,使得firs不為0,所以最好使用 //first給i動態賦值, for (int i = first; i < first+size() ; i++) { System.out.println("arr["+i%maxSize+"]"+arr[i%maxSize]); }
7.獲取佇列中資料的總個數:
public int dataNum(){ //韓順平老師的教程上是這樣寫,但是我理解不了..........。 return (last+maxSize-first) % maxSize; }
8.檢視隊首資料但不彈出:
public void seeFirstData(){ return arr[first]; }
全部程式碼整合:
package 練習; import java.util.Scanner; public class CircleArryQueue { public static void main(String[] args){ CircleQueue circleQueue = new CircleQueue(4); System.out.println("--------測試環形佇列--------"); char key = ' '; Scanner scanner = new Scanner(System.in); boolean flag = true; while (flag){ System.out.println("s(showAllData):檢視佇列資料"); System.out.println("p(pushData):隊尾新增資料"); System.out.println("g(popData):彈出隊頭資料"); System.out.println("h(seefirstData):獲取隊頭資料"); System.out.println("e(exit):退出程式"); key = scanner.next().charAt(0); switch (key){ case 's': circleQueue.showAllData(); break; case 'p': System.out.println("輸入一個數據:"); int obj = scanner.nextInt(); circleQueue.pushData(obj); break; case 'g': circleQueue.popData(); break; case 'h': circleQueue.seeFirstData(); break; case 'e': scanner.close(); flag = false; break; default: break; } } System.out.println("程式結束~~~"); } } class CircleQueue { private int maxSize ; //陣列長度,即佇列最大容量 private int first; //頭指標,控制出隊操作 private int last; //尾指標,控制入隊操作 private int[] arr; //陣列型別,可以換其他的。 //構造器初始化資訊 public CircleQueue(int maxSize){ this.maxSize = maxSize; this.arr = new int[maxSize]; this.first = 0; //這兩個可以不加,不叫也是預設為0 this.last = 0; } public boolean isEmpty(){ //頭指標和尾指標一樣 則說明為空 return last == first; } /* *這裡的 last+1 主要是為了讓指標後移,特別是在佇列尾部新增資料的時候,本來用last也可以判斷但 *是一開始還沒加資料的時候,如果直接用last % maxSize == first,結果是true,所以為了解決指標 *後移和判斷是否滿,用來last+1。其次,因為last+1可能會導致陣列指標越界,所以用取模來控制它 *的範圍,同時保證他會在一個固定的範圍迴圈變換,也利於環形佇列的實現。 */ public boolean isFull(){ return (last + 1) % maxSize == first; } public void pushData(int data){ //先判斷是否滿了 if(isFull()){ System.out.println("佇列已經滿啦~~"); return; } arr[last] = data; //last+1是為了後移,取模是為了避免指標越界,同時可以讓指標迴圈 last = (last + 1) % maxSize; } public int popData(){ if (isEmpty()) { //拋異常就可以不用返回資料了 throw new RuntimeException("佇列為空,沒有獲取到資料~~"); } //要先把first對應的陣列資料儲存——>first後移——>返回資料 int value = arr[first]; //first+1的操作和last+1是一樣的,取模也是 first = (first+1) % maxSize; System.out.println(value); return value; //如果不儲存first指標 那麼返回的資料就不對了 //如果直接返回資料,那first指標還沒後移 也不對,所以需要使用第三方變數 } //檢視所有資料 public void showAllData(){ if (isEmpty()) { System.out.println("佇列為空,沒有資料~~"); } //此處i不為0,是因為有可能之前有過popData()操作,使得firs不為0,所以最好使用 //first給i動態賦值, for (int i = first; i < first+dataNum() ; i++) { System.out.println("arr["+i%maxSize+"]"+arr[i%maxSize]); } } //檢視有效資料個數 public int dataNum(){ //韓順平老師的教程上是這樣寫,但是我理解不了..........。 return (last+maxSize-first) % maxSize; } //檢視佇列第一個資料 public int seeFirstData(){ System.out.println(arr[first]); return arr[first]; } }
最後:
部分內容參考自B站韓順平老師java資料結構課程,由於筆者水平有限,整理的博文中難免有不不足和理解不對的地方,歡迎留言批評指正。碼字不易,除錯費神。歡迎轉載轉發,但請註明出處。如有幫助,歡迎打賞一杯咖啡除錯bug。
相關推薦
Java 單向佇列及環形佇列
佇列的特點 1.可以使用陣列和連結串列兩種方式來實現。 2.遵循先入先出(FIFO)的規則,即先進入的資料先出。 3.屬於有序列表。 圖解實現過程: 1.定義一個固定長度的陣列,長度為maxSize。 2.設定兩個指標first = -1(指向佇列第一個資料的前一位,這樣保證在新增第一 個數據
佇列及迴圈佇列(Java實現)
package ch03; /* * 佇列類 */ public class MyQueue { // 底層實現是一個數組 private long[] arr; // 有效資料大小 private int elements; // 隊頭 priva
棧、佇列及優先順序佇列
抽象資料型別(ADT) 陣列、連結串列、樹等等都適用於資料庫應用中作資料記錄,常用來記錄對應於現實世界的資料;而棧、佇列及優先順序佇列更多地是作為程式設計師的工具來使用(用最合適的工具幹活),以簡化某些程式操作。 棧、佇列及優先順序佇列都可以使用陣列連結串列來實現,優先順序佇列通常使用堆實現。 在棧、佇
順序佇列及鏈佇列
一、實驗目的1.掌握佇列的連結儲存結構—鏈佇列以及順序儲存結構—順序佇列2.驗證鏈佇列的儲存結構和基本的實現3.驗證佇列的操作特性。二、實驗內容1.建立一個空佇列2.對已建立的佇列進行插入、刪除、取隊頭元素等操作三、設計與編碼1.理論知識定義鏈佇列和順序佇列的資料型別如入隊出
python3佇列及迴圈佇列基本實現
class Queue(object):# 定義佇列類 為什麼加入object def __init__(self,size): self.size = size #定義佇列長度
順序佇列及鏈佇列的基本操作實現
一、實驗目的 1、熟練佇列的結構特點,掌握佇列的順序儲存和鏈式儲存結構和實現。 2、 學會使用佇列解決實際問題。 二、實驗內容 自己確定結點的具體資料型別和問題規模: 分別建立一個順序佇列和鏈佇列,實現佇列的入隊和出隊操作。 三、實驗步驟 1、依據實驗內
java併發包訊息佇列及在開源軟體中的應用
1.BlockingQueue的常用方法 BlockingQueue也是java.util.concurrent下的主要用來控制執行緒同步的工具。 主要的方法是:put、take一對阻塞存取;add、poll一對非阻塞存取。 插入: 1
java資料結構——環形佇列
ArrayQueue存在一個問題,假設當尾部插入元素滿了,頭部又刪掉了一些元素,這種情況下,就誤認為空間滿了,造成了假溢位,實際上頭部刪除了元素留出了空間。這時候環形佇列就解決了這樣的一個問題,環形
golang 實現一種環形佇列,及週期任務
一、環形佇列 環形佇列不同語言有很多種不同的實現,不過大部分都比較複雜。 在使用golang實踐生產者消費者模型時,發現了一種變相的環形佇列,程式碼比“常規的”環形佇列簡單的多,解決2個問題: 1、生產者消費者間資料傳遞; 2、記憶體空間預申請,避免頻繁的動態記
Java實現環形佇列
這裡我定義的環形佇列為:列表中最後一個元素是指向列表中的第一個元素,而且裡面提供一個next方法,可以不斷獲取下一個元素,在環形佇列中也就是不斷的轉圈,實現方式如下: 佇列中提供的方法: public boolean add(E e):加入佇列
java之環形佇列的實現
/** * Array-based implementation of the queue. * @author zhang yin ye *@email:[email protected] */ public class ArrayQueue&l
Java實現環形佇列(入隊、出隊)
public class Class_queue { private int q_head; private int q_tail; private int[] queue; private int len; private int
Java併發包原始碼學習系列:CLH同步佇列及同步資源獲取與釋放
[toc] ## 本篇學習目標 - 回顧CLH同步佇列的結構。 - 學習獨佔式資源獲取和釋放的流程。 ## CLH佇列的結構 我在[Java併發包原始碼學習系列:AbstractQueuedSynchronizer#同步佇列與Node節點](https://www.cnblogs.com/summer
資料結構JAVA版之棧和佇列
一、涉及的內容大綱 二、簡單介紹棧、佇列和其他資料結構的不同 1 對於其他的資料結構而言,都適用與資料庫應用中作資料記錄。但是因為棧和佇列的生命週期比那些資料庫型別的資料結構要短,所以他們只是在程式的操作期間才會建立和執行,在完成任務之後就會被銷燬。所以棧和佇列更多的是用於構思演算法的
堆的應用及優先佇列
標頭檔案: #include<queue> 宣告: priority_queue <int> i; priority_queue <double> d; 預設為大根堆,即從大到小排列。 除非: priority_queue &
[LeetCode] Design Circular Queue 設計環形佇列
Design your implementation of the circular queue. The circular queue is a linear data structure in which the operations are performed based on FIFO
Java用連結串列實現佇列
佇列--先入先出 棧---後入先出 連結串列實現佇列和棧。首先我們需要構建一個連結串列。連結串列有哪幾要素? 1、連結串列本身的value 2、連結串列的next指標,next指標指的還是同樣型別的值。 下邊看程式碼 public class Element&l
Java---之實現資料結構----佇列
package 資料結構;//java之實現佇列 class quene{ private class Data{ private Object obj; private Data next=null; Data(Object obj){
Java併發環境下的佇列(Queue)概述
本文作者:王一飛,叩丁狼高階講師。原創文章,轉載請註明出處。 概念 佇列 佇列是一種特殊的線性表,是一種先進先出(FIFO)的資料結構。它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作。進行插入操作的端稱為隊尾,進行刪除操
uvaoj 133 - The Dole Queue(邏輯,環形佇列數數)
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=69 有n個人向內排成一圈,從一個位置開始逆時針數k個,第k個出隊,從一個位置開始順時針數m