摘要:隊列的操作方式和棧類似,唯一的區別在于隊列只允許新數據在后端進行添加。
前言
看過筆者前兩篇介紹的Java版數據結構數組和棧的盆友,都給予了筆者一致的好評,在這里筆者感謝大家的認可?。?!
由于本章介紹的數據結構是隊列,在隊列的實現上會基于前面寫的動態數組來實現,而隊列又和棧不論是從特點上和操作上都有類似之處,所以在這里對這兩種數據結構不了解的朋友,可以去看一下筆者前兩篇文章介紹的數據結構數組和棧,這里筆者把鏈接貼出來(看過的盆友可以跳過此步驟...)
Java版-數據結構-數組
Java版-數據結構-棧
介紹隊列是一種特殊的線性表,它只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。
隊列的操作方式和棧類似,唯一的區別在于隊列只允許新數據在后端(rear)進行添加。
特點隊列是一種線性結構
只能從一端(隊尾)添加元素,從另一端(隊首)取出元素
先進先出,First In First Out(FIFO)
之前在介紹棧的時候,通過示意圖來幫助大家了解什么是棧;這里,我仍采用示意圖形式向大家演示隊列常用的兩個操作:入隊操作和出隊操作。
隊列入隊操作
這里我們可以形象地想成我們到銀行辦理業務排隊的場景,現在A、B、C三個元素分別到銀行柜臺排成一條隊辦理業務(我們都是文明的孩紙,總不能插隊O(∩_∩)O哈?。?,依次排隊的元素是:A、B、C。
隊列出隊操作
當元素A辦理完業務時,當前是元素A先離開隊列,然后是元素B,最后是元素C
我們時刻要牢記隊列,入隊是從隊尾一端進行入隊,出隊是從隊首一端進行出隊,是一種:先進先出的數據結構。
本文會介紹隊列的兩張實現方式,一種是數組隊列,另外一種是循環隊列,考慮篇幅長度原因,本篇我們暫時只介紹數組隊列,循環隊列放在下一篇介紹。
數組隊列(底層基于數組實現)現在我們聲明一個數組的長度(capacity=3),元素個數為(size=0)的int類型數組的空隊列,在這里,假設對隊列的隊首為數組的左側,隊尾為數組的右側,示意圖如下:
現在如果我們有四個元素:A、B、C、D要入隊
元素A入隊
元素A已經入隊了,現在開始元素B入隊
元素A和元素B已經入隊了,現在開始元素C入隊
元素A、B和C已經分別入隊了,現在如果我們要開始元素D入隊,根據我們之前定義的動態數組的特性,如果元素D進行入隊操作,會發現此時我們的數組已經滿了,這時候數組會自動地擴容(擴容的原理:新建一個容量是原數組容量兩倍的數組,把原數組中的元素依次拷貝到新的數組中,最后引用指向新的數組)的原來的兩倍(具體擴容多少,盆友可以自行設置)示意圖如下:
到這里我們已經完成了元素:A、B、C、D的入隊操作了,現在我們來看一下,它們的出隊操作,根據隊列的特性,隊列是一種先進先出的數據結構,之前入隊操作順序依次是:A->B->C->D,那么出隊操作順序仍然是:A->B->C->D
現在我們來看一下元素A和元素B出隊后的示意圖:
元素C和D的出隊原理和元素A出隊的原理一樣,直至全部出隊完成,變成空隊列
在元素出隊的過程中,相應地也會進行縮容操作,之前筆者這邊定義,當數組中元素的個數(size)等于數組容量(capacity)的一半時,數組會進行縮容操作,這也正是動態數組的特點。
了解了數組隊列的底層原理之后,接下來我們用代碼來實現一下(建議盆友,在看之前,自己可以嘗試寫一下,然后在看,這樣印象可能會比較深刻O(∩_∩)O哈?。?/p>
向隊列中添加元素(入隊)
void enqueue(E e);
從隊列中取出元素(出隊)
E dequeue();
獲取隊首元素
E getFront();
獲取隊列中元素個數
int getSize();
判斷隊列是否為空
boolean isEmpty();
接口定義 :Queue
public interface Queue{ /** * 入隊 * * @param e */ void enqueue(E e); /** * 出隊 * * @return */ E dequeue(); /** * 獲取隊首元素 * * @return */ E getFront(); /** * 獲取隊列中元素的個數 * * @return */ int getSize(); /** * 判斷隊列是否為空 * * @return */ boolean isEmpty(); }
DynamicArrayQueue
public class DynamicArrayQueueimplements Queue { /** * 用數組存放隊列中元素的個數 */ private DynamicArray dynamicArray; /** * 指定容量,初始化隊列 * * @param capacity */ public DynamicArrayQueue(int capacity) { dynamicArray = new DynamicArray<>(capacity); } /** * 默認容量,初始化隊列 */ public DynamicArrayQueue() { dynamicArray = new DynamicArray<>(); } @Override public void enqueue(E e) { dynamicArray.addLast(e); } @Override public E dequeue() { return dynamicArray.removeFirst(); } @Override public E getFront() { return dynamicArray.getFirst(); } @Override public int getSize() { return dynamicArray.getSize(); } @Override public boolean isEmpty() { return dynamicArray.isEmpty(); } @Override public String toString() { return "DynamicArrayQueue{" + "【隊首】dynamicArray=" + dynamicArray + "}【隊尾】"; } }
測試類: DynamicArrayQueueTest
public class DynamicArrayQueueTest { @Test public void testArrayQueue() { // 指定容量(capacity=6)初始化隊列 DynamicArrayQueuedynamicArrayQueue = new DynamicArrayQueue(3); System.out.println("初始隊列:" + dynamicArrayQueue); // 準備入隊元素 List enQueueElements = Arrays.asList("A", "B", "C"); // 元素入隊 enQueueElements.forEach(x -> dynamicArrayQueue.enqueue(x)); System.out.println("元素A、B、C入隊:" + dynamicArrayQueue); // 此時如果又有一個元素D入隊,會發生擴容操作 (size == capacity)進行擴容 dynamicArrayQueue.enqueue("D"); System.out.println("元素D入隊,發生擴容:" + dynamicArrayQueue); // 元素A出隊,會發生縮容操作(size == capacity / 2)進行縮容 dynamicArrayQueue.dequeue(); System.out.println("元素A出隊,發生縮容:" + dynamicArrayQueue); // 元素B出隊 dynamicArrayQueue.dequeue(); System.out.println("元素B出隊:" + dynamicArrayQueue); } }
運行結果
初始隊列:DynamicArrayQueue{【隊首】dynamicArray=DynamicArray{data=[null, null, null], size=0,capacity=3}}【隊尾】 元素A、B、C入隊:DynamicArrayQueue{【隊首】dynamicArray=DynamicArray{data=[A, B, C], size=3,capacity=3}}【隊尾】 元素D入隊,發生擴容:DynamicArrayQueue{【隊首】dynamicArray=DynamicArray{data=[A, B, C, D, null, null], size=4,capacity=6}}【隊尾】 元素A出隊,發生縮容:DynamicArrayQueue{【隊首】dynamicArray=DynamicArray{data=[B, C, D], size=3,capacity=3}}【隊尾】 元素B出隊:DynamicArrayQueue{【隊首】dynamicArray=DynamicArray{data=[C, D, null], size=2,capacity=3}}【隊尾】
細心的盆友,會發現,因為隊列的底層是數組來實現的,隊列的出隊操作實際上就是:刪除數組中的第一個元素,后面的所有元素都要往前面挪一位;其實這樣性能是比較低下的,時間復雜度是O(n)級別的。我們想如果元素進行出隊操作后,能否不挪動后面的元素,還能維持隊列的特性,這樣問題不就解決了嗎?盆友可以自行思考一下。
完整版代碼GitHub倉庫地址:Java版數據結構-隊列(數組隊列) 歡迎大家【關注】和【Star】
本篇完成的數組隊列是基于之前【Java版-數據結構-數組】動態數組來實現的,下一篇筆者會給大家介紹用循環隊列來解決數組隊列帶來的性能問題。接下來,筆者還會一一的實現其它常見的數組結構。
靜態數組
動態數組
棧
數組隊列
循環隊列
鏈表
循環鏈表
二分搜索樹
優先隊列
堆
線段樹
字典樹
AVL
紅黑樹
哈希表
....
持續更新中,歡迎大家關注公眾號:小白程序之路(whiteontheroad),第一時間獲取最新信息?。?!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73942.html
摘要:為了方便大家查閱,筆者在這里貼出相關的地址版數據結構數組版數據結構棧版數據結構隊列數組隊列為了解決數組隊列帶來的問題,本篇給大家介紹一下循環隊列。 前情回顧 在上一篇,筆者給大家介紹了數組隊列,并且在文末提出了數組隊列實現上的劣勢,以及帶來的性能問題(因為數組隊列,在出隊的時候,我們往往要將數組中的元素往前挪動一個位置,這個動作的時間復雜度O(n)級別),如果不清楚的小伙伴歡迎查看閱讀...
摘要:純分享直接上干貨操作系統并發支持進程管理內存管理文件系統系統進程間通信網絡通信阻塞隊列數組有界隊列鏈表無界隊列優先級有限無界隊列延時無界隊列同步隊列隊列內存模型線程通信機制內存共享消息傳遞內存模型順序一致性指令重排序原則內存語義線程 純分享 , 直接上干貨! 操作系統并發支持 進程管理內存管...
摘要:單線程集合本部分將重點介紹非線程安全集合。非線程安全集合框架的最新成員是自起推出的。這是標準的單線程陣營中唯一的有序集合。該功能能有效防止運行時造型。檢查個集合之間不存在共同的元素?;谧匀慌判蚧蛘页黾现械淖畲蠡蜃钚≡?。 【編者按】本文作者為擁有十年金融軟件開發經驗的 Mikhail Vorontsov,文章主要概覽了所有標準 Java 集合類型。文章系國內 ITOM 管理平臺 O...
摘要:面試題從尾到頭打印鏈表輸入一個鏈表,從尾到頭打印鏈表每個節點的值面試題重建二叉樹輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。例如輸入前序遍歷序列和中序遍歷序列,則重建二叉樹并返回。隊列中的元素為類型。其中負數用補碼表示。 面試題2 單例(之前有整理,略) 面試題3 二維數組中的查找 public boolean find(int target, int [][] arra...
摘要:介紹棧是一種后進先出的線性表數據結構,分為棧頂和棧底兩端,僅允許在表的一端插入元素,這一端被稱為棧頂,另外一端稱之為棧底。 介紹 棧是一種后進先出的線性表數據結構,分為棧頂和棧底兩端,僅允許在表的一端插入元素,這一端被稱為棧頂,另外一端稱之為棧底。棧,只有兩種操作,分為入棧(壓棧)和出棧(退棧);向棧中添加元素的操作叫做入棧,相反從棧中刪除元素叫做出棧。 特點 只能從棧頂添加元素或者...
閱讀 1270·2023-04-25 19:10
閱讀 1146·2021-09-10 10:50
閱讀 3034·2021-09-02 15:21
閱讀 1388·2019-08-30 15:52
閱讀 1686·2019-08-30 13:56
閱讀 2090·2019-08-30 12:53
閱讀 1876·2019-08-28 18:22
閱讀 2128·2019-08-26 13:47