Deque(隊列)



Deque

概述

一個線性 collection,支持在兩端插入和移除元素。名稱 deque 是“double ended queue(雙端隊列)”的縮寫,通常讀為“deck”。大多數 Deque 實現對於它們能夠包含的元素數沒有固定限制,但此接口既支持有容量限制的雙端隊列,也支持沒有固定大小限制的雙端隊列。


特點

  1. Deque是一個Queue的子接口,是一個雙端隊列,支持在兩端插入和移除元素
  2. deque支持索引值直接存取。
  3. Deque頭部和尾部添加或移除元素都非常快速。但是在中部安插元素或移除元素比較費時。
  4. 插入、刪除、獲取操作支持兩種形式:快速失敗和返回nulltrue/false
  5. 不推薦插入null元素,null作為特定返回值表示隊列為空

常用方法

第一個元素(頭部) 最后一個元素(尾部)
拋出異常 特殊值 拋出異常 特殊值
插入 addFirst(e) offerFirst(e) addLast(e) offerLast(e)
移除 removeFirst() pollFirst() removeLast() pollLast()
檢查 getFirst() peekFirst() getLast() peekLast()

雙向隊列操作

插入元素
  • addFirst(): 向隊頭插入元素,如果元素為null,則發生空指針異常
  • addLast(): 向隊尾插入元素,如果為空,則發生空指針異常
  • offerFirst(): 向隊頭插入元素,如果插入成功返回true,否則返回false
  • offerLast(): 向隊尾插入元素,如果插入成功返回true,否則返回false
移除元素
  • removeFirst(): 返回並移除隊頭元素,如果該元素是null,則發生NoSuchElementException
  • removeLast(): 返回並移除隊尾元素,如果該元素是null,則發生NoSuchElementException
  • pollFirst(): 返回並移除隊頭元素,如果隊列無元素,則返回null
  • pollLast(): 返回並移除隊尾元素,如果隊列無元素,則返回null
獲取元素
  • getFirst(): 獲取隊頭元素但不移除,如果隊列無元素,則發生NoSuchElementException
  • getLast(): 獲取隊尾元素但不移除,如果隊列無元素,則發生NoSuchElementException
  • peekFirst(): 獲取隊頭元素但不移除,如果隊列無元素,則返回null
  • peekLast(): 獲取隊尾元素但不移除,如果隊列無元素,則返回null
棧操作

pop(): 彈出棧中元素,也就是返回並移除隊頭元素,等價於removeFirst(),如果隊列無元素,則發生NoSuchElementException

push(): 向棧中壓入元素,也就是向隊頭增加元素,等價於addFirst(),如果元素為null,則發生NoSuchElementException,如果棧空間受到限制,則發生IllegalStateException

引用場景
  1. 滿足FIFO場景時
  2. 滿足LIFO場景時,曾經在解析XML按標簽時使用過棧這種數據結構,但是卻選擇Stack類,如果在進行棧選型時,更推薦使用Deque類,應為Stack是線程同步

ArrayDeque

概述

Deque 接口的大小可變數組的實現。數組雙端隊列沒有容量限制;它們可根據需要增加以支持使用。它們不是線程安全的;在沒有外部同步時,它們不支持多個線程的並發訪問。禁止 null 元素。此類很可能在用作堆棧時快於 Stack,在用作隊列時快於 LinkedList

特點
  1. 初始容量為16,每次擴容都會翻倍,並且容量一定是2^n。
public ArrayDeque() {
        elements = new Object[16];
    }
 public ArrayDeque(int numElements) {
        allocateElements(numElements);
    }
 private void allocateElements(int numElements) {
        int initialCapacity = MIN_INITIAL_CAPACITY;
        // Find the best power of two to hold elements.
        // Tests "<=" because arrays aren't kept full.
        if (numElements >= initialCapacity) {
            initialCapacity = numElements;
            initialCapacity |= (initialCapacity >>>  1);
            initialCapacity |= (initialCapacity >>>  2);
            initialCapacity |= (initialCapacity >>>  4);
            initialCapacity |= (initialCapacity >>>  8);
            initialCapacity |= (initialCapacity >>> 16);
            initialCapacity++;

            if (initialCapacity < 0)   // Too many elements, must back off
                initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
        }
        elements = new Object[initialCapacity];
    }

>>>是無符號右移操作,|是位或操作,經過五次右移和位或操作可以保證得到大小為 2^n-1 的數。最后在自增一,就是 2^n。

  1. 增加或刪除(head)
public void addFirst(E e) {
        if (e == null)
            throw new NullPointerException();
        elements[head = (head - 1) & (elements.length - 1)] = e;//注意點
        if (head == tail)
            doubleCapacity();
    }
elements[head = (head - 1) & (elements.length - 1)] = e;

當head為0時,實際上是11111111&00001111,結果是00001111,也就是物理數組的尾部15;當head增長如head+1超過物理數組長度如16時,實際上是00010000&00001111,結果00000000,也就是0,這樣就回到了物理數組的頭部.

相當於head初始值0時,第一次就將head指針定位到數組末尾了,然后指針從后向前移動。

而addLast就與之相反,控制tail指針,從前向后移動。當tail和head相遇了就說明空間已經滿了。(就像一個圓環結構)


以上

@Fzxey


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM