Java版-數據結構-隊列(數組隊列)

前言

看過筆者前兩篇介紹的Java版數據結構數組的盆友,都給予了筆者一致的好評,在這裏筆者感謝你們的承認!!!前端

因爲本章介紹的數據結構是隊列,在隊列的實現上會基於前面寫的動態數組來實現,而隊列又和不管是從特色上和操做上都有相似之處,因此在這裏對這兩種數據結構不瞭解的朋友,能夠去看一下筆者前兩篇文章介紹的數據結構數組,這裏筆者把連接貼出來(看過的盆友能夠跳過此步驟...)java

介紹

隊列是一種特殊的線性表,它只容許在表的前端(front)進行刪除操做,而在表的後端(rear)進行插入操做,和棧同樣,隊列是一種操做受限制的線性表。進行插入操做的端稱爲隊尾,進行刪除操做的端稱爲隊頭。git

隊列的操做方式和相似,惟一的區別在於隊列只容許新數據在後端(rear)進行添加。github

特色

  • 隊列是一種線性結構
  • 只能從一端(隊尾)添加元素,從另外一端(隊首)取出元素
  • 先進先出,First In First Out(FIFO)

以前在介紹棧的時候,經過示意圖來幫助你們瞭解什麼是棧;這裏,我仍採用示意圖形式向你們演示隊列經常使用的兩個操做:入隊操做出隊操做後端

隊列入隊操做數組

image-20190314004824471

這裏咱們能夠形象地想成咱們到銀行辦理業務排隊的場景,如今A、B、C三個元素分別到銀行櫃檯排成一條隊辦理業務(咱們都是文明的孩紙,總不能插隊O(∩_∩)O哈!),依次排隊的元素是:A、B、C。數據結構

隊列出隊操做ide

image-20190314004945601

當元素A辦理完業務時,當前是元素A先離開隊列,而後是元素B,最後是元素C性能

咱們時刻要牢記隊列,入隊是從隊尾一端進行入隊,出隊是從隊首一端進行出隊,是一種:先進先出的數據結構。測試

本文會介紹隊列的兩張實現方式,一種是數組隊列,另一種是循環隊列,考慮篇幅長度緣由,本篇咱們暫時只介紹數組隊列,循環隊列放在下一篇介紹。

數組隊列(底層基於數組實現

底層原理分析

如今咱們聲明一個數組的長度(capacity=3),元素個數爲(size=0)的int類型數組的空隊列,在這裏,假設對隊列的隊首爲數組的左側隊尾爲數組的右側,示意圖以下:

image-20190314023306672

如今若是咱們有四個元素:A、B、C、D要入隊

元素A入隊

image-20190314025039492

元素A已經入隊了,如今開始元素B入隊

image-20190314025109889

元素A和元素B已經入隊了,如今開始元素C入隊

image-20190314055125456

元素ABC已經分別入隊了,如今若是咱們要開始元素D入隊,根據咱們以前定義的動態數組的特性,若是元素D進行入隊操做,會發現此時咱們的數組已經滿了,這時候數組會自動地擴容(擴容的原理:新建一個容量是原數組容量兩倍的數組,把原數組中的元素依次拷貝到新的數組中,最後引用指向新的數組)的原來的兩倍(具體擴容多少,盆友能夠自行設置)示意圖以下:

image-20190314055438791

到這裏咱們已經完成了元素:A、B、C、D的入隊操做了,如今咱們來看一下,它們的出隊操做,根據隊列的特性,隊列是一種先進先出的數據結構,以前入隊操做順序依次是:A->B->C->D,那麼出隊操做順序仍然是:A->B->C->D

如今咱們來看一下元素A和元素B出隊後的示意圖:

image-20190314060105701

元素CD的出隊原理和元素A出隊的原理同樣,直至所有出隊完成,變成空隊列

在元素出隊的過程當中,相應地也會進行縮容操做,以前筆者這邊定義,當數組中元素的個數(size)等於數組容量(capacity)的一半時,數組會進行縮容操做,這也正是動態數組的特色。

瞭解了數組隊列的底層原理以後,接下來咱們用代碼來實現一下(建議盆友,在看以前,本身能夠嘗試寫一下,而後在看,這樣印象可能會比較深入O(∩_∩)O哈!)

隊列基本操做
  • 向隊列中添加元素(入隊)
void enqueue(E e);
複製代碼
  • 從隊列中取出元素(出隊)
E dequeue();
複製代碼
  • 獲取隊首元素
E getFront();
複製代碼
  • 獲取隊列中元素個數
int getSize();
複製代碼
  • 判斷隊列是否爲空
boolean isEmpty();
複製代碼
代碼實現

接口定義Queue

public interface Queue<E> {
    /** * 入隊 * * @param e */
    void enqueue(E e);

    /** * 出隊 * * @return */
    E dequeue();

    /** * 獲取隊首元素 * * @return */
    E getFront();

    /** * 獲取隊列中元素的個數 * * @return */
    int getSize();

    /** * 判斷隊列是否爲空 * * @return */
    boolean isEmpty();
}
複製代碼

DynamicArrayQueue 類實現接口 Queue

public class DynamicArrayQueue<E> implements Queue<E> {

    /** * 用數組存放隊列中元素的個數 */
    private DynamicArray<E> 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)初始化隊列
        DynamicArrayQueue<String> dynamicArrayQueue = new DynamicArrayQueue(3);
        System.out.println("初始隊列:" + dynamicArrayQueue);

        // 準備入隊元素
        List<String> 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),第一時間獲取最新信息!!!

相關文章
相關標籤/搜索