java基礎容器學習之雙端隊列ArrayDeque

2020-12-08 暖爸的java家園

引言:

ArrayDeque,被稱為「雙端隊列」,可以從兩端進行插入或刪除操作,當需要使用棧時,Java已不推薦使用Stack,而是推薦使用更高效的ArrayDeque,當需要使用隊列時也可以使用ArrayDeque。

ArrayDeque類簡介:

Deque的含義是「double ended queue」,即雙端隊列。它可以實現棧和隊列的功能,存在以下這些方法的關係:

隊列方法 雙端隊列方法

add(e) addLast(e)

offer(e) offerLast(e)

remove() removeFirst()

poll() pollFirst()

element() getFirst()

peek() peekFirst()

棧方法 雙端隊列方法

push(e) addFirst(e)

pop() removeFirst()

peek() peekFirst()

很明顯的,ArrayDeque類就是一個實現了兩頭插入刪除的隊列。

ArrayDeque類屬性:

主要屬性如下所示,為存放元素的數組elements,頭的索引位置head,尾的索引位置tail。

transient Object[] elements;

transient int head;

transient int tail;

ArrayDeque類的具體結構如下圖所示:

ArrayDeque結構

ArrayDeque的數組是循環數組,就是可以head在後,tail在前。

ArrayDeque類的數組容量:

如下源碼所示,ArrayDeque的數組容量由構造函數中調用allocateElements獲取,而allocateElements方法的邏輯如下:

-1. 如果傳入的容量參數numElements小於8,則使用8作為默認的容量。

-2.如果numElements>=8(且numElements<2的30次方),則取numElements的下一個2的指數的值作為容量。

-3.如果numElements>=2的30次,則取2的30次作為容量。

舉個慄子:

numElements=9,

二進位為00000000 00000000 00000000 00001001

語句1後,結果為

00000000 00000000 00000000 00001101

語句2後,結果為

00000000 00000000 00000000 00001111

語句3,4,5執行後結果還是這個,就是15,再++就是16。

而numElements>=2的30次,則得到的結果為initialCapacity為-1,就是10000000 00000000 00000000 00000000,則右移一位,就是結果:01000000 00000000 00000000 00000000,2的30次。

private static final int MIN_INITIAL_CAPACITY = 8;

private void allocateElements(int numElements) {

int initialCapacity = MIN_INITIAL_CAPACITY;

if (numElements >= initialCapacity) {

initialCapacity = numElements;

initialCapacity |= (initialCapacity >>> 1);//1

initialCapacity |= (initialCapacity >>> 2);//2

initialCapacity |= (initialCapacity >>> 4);//3

initialCapacity |= (initialCapacity >>> 8);//4

initialCapacity |= (initialCapacity >>> 16);//5

initialCapacity++;

if (initialCapacity < 0)

initialCapacity >>>= 1;

}

elements = new Object[initialCapacity];

}

總結:ArrayDeque的容量總為2的指數,默認是8,構造函數時不必刻意傳入2的指數,會自動計算。

如果傳入的值>=2的30次,則使用最大容量2的30次。

ArrayDeque類的元素插入操作:

如下代碼所示,為插入元素的操作,主要注意的是下標不能為越界。

這裡使用(head - 1) & (elements.length - 1) 這樣的方式來防止越界,elements.length - 1為低位全為1的二進位,與head-1做與運算,得到結果即可。

尾部插入操作也類似,都比較簡單。

如下圖所示:

addFirst操作

public void addFirst(E e) {

if (e == null)

throw new NullPointerException();

elements[head = (head - 1) & (elements.length - 1)] = e;

if (head == tail)

doubleCapacity();

}

ArrayDeque類的擴容操作:

如下代碼所示,擴容操作主要分兩部分,容量申請為原來的兩倍,將head右邊的數據複製,將head左邊的數據複製。

private void doubleCapacity() {

assert head == tail;

int p = head;

int n = elements.length;

int r = n - p; // number of elements to the right of p

int newCapacity = n << 1;

if (newCapacity < 0)

throw new IllegalStateException("Sorry, deque too big");

Object[] a = new Object[newCapacity];

System.arraycopy(elements, p, a, 0, r);

System.arraycopy(elements, 0, a, r, p);

elements = a;

head = 0;

tail = n;

}

ArrayDeque類已基本介紹完畢,後續還有許多java容器的類,下次介紹。

相關焦點

  • C++ 順序容器基礎知識總結
    所以本文僅僅是對容器基礎知識的歸納。至於容器提供的接口與使用實例,建議查取官方文檔。文章難免有錯漏,希望指出。1、容器概論容器,置物之所也。像桶可裝水,碗可盛湯,C++的容器,可以存儲對象。容器有多種,用來處理不同的元素操作訴求。按照元素存儲到容器中以及訪問方式的差異,容器分為順序容器與關聯容器。順序容器也稱為序列式容器。
  • java並發編程之深入學習Concurrent包(十三,雙端阻塞隊列)
    引言:春節疫情的關係,宅在家,有空學習一下java並發中的內容,順便發出來請大家一起瞅瞅。上一章學習了阻塞隊列,這次一起學習下雙端阻塞隊列。LinkedBlockingDeque簡介:LinkedBlockingDeque是雙向鍊表實現的雙端阻塞隊列。該阻塞隊列可以從隊列的頭和尾進行插入和刪除,且該阻塞隊列是線程安全的。
  • java 基礎 之 集合ArrayList和Vector
    今天我們繼續學習集合中的其他數據類型。今天我們主要看下線性表。在java中的線性表是如何實現的呢。
  • 死磕 java所有集合之終結篇
    點擊下面連結可以直接到相應的章節查看:死磕 java集合之HashMap源碼分析死磕 java集合之LinkedHashMap源碼分析死磕 java集合之WeakHashMap源碼分析死磕 java集合之TreeMap源碼分析(一)死磕 java集合之TreeMap源碼分析(二)死磕 java集合之TreeMap
  • Java中常用隊列的總結
    Java隊列總結通過前面文章的學習,我們對Java中常用隊列做了介紹。本文,咱們來對隊列做個總結吧。首先,我們介紹了現實生活中的實際場景(排隊買票等),來告訴我們為什麼需要使用隊列。隊列是一種先進先出(FIFO)的抽象數據結構,在Java中,隊列使用了兩種數據類型來實現的,分別是:數組和鍊表這兩種數據結構。本文主要內容:回顧Java中常用的七個阻塞隊列進行總結及阻塞隊列中四組AP並進行總結。本文來源:本文是由凱哥Java(kaigejava)原創發布。
  • 淺談C++下STL庫中的容器底層小知識
    STL下的常見容器主要分為兩大類:序列式容器以及關聯式容器。顧名思義序列式容器就是在物理上一個挨著一個的,彼此之間相鄰,比如數組、棧、隊列,其實都是一個挨著一個的。而關聯式容器,重點在關聯二字,關聯關聯,至少是兩個東西之間存在著一定的聯繫才可以叫做關聯,比如map中的key和value有著一定的關聯。
  • java集合詳解合集
    所以的集合類都位於java.util包下,後來為了處理多線程環境下的並發安全問題,java5還在java.util.concurrent包下提供了一些多線程支持的集合類。在學習Java中的集合類的API、編程原理的時候,我們一定要明白,"集合"是一個很古老的數學概念,它遠遠早於Java的出現。
  • C++(STL):17---deque之迭代器使用
    表 1 deque 支持迭代器的成員函數成員函數功能begin()返回指向容器中第一個元素的正向迭代器;如果是 const 類型容器,在該函數返回的是常量正向迭代器。end()返回指向容器最後一個元素之後一個位置的正向迭代器;如果是 const 類型容器,在該函數返回的是常量正向迭代器。此函數通常和 begin() 搭配使用。
  • 【技術定投】四兩撥千斤的Heap和Deque
    以此為基礎,再考慮1439. Find the Kth Smallest Sum of a Matrix With Sorted Rows,就比較容易理解了。題目中的m、n、k都不大,所以建優先隊列完全是可行的。最後計算完所有行後第k小的數字的和即為所求。因為每一行都會進行k次出入堆操作,所以O(m*k*logk)。然後再來看Deque,這裡要說的是上一周的最後一題1425. Constrained Subsequence Sum。
  • Java多線程並發編程中並發容器第二篇之List的並發類講解
    Java多線程並發編程中並發容器第二篇之List的並發類講解概述本文我們將詳細講解list對應的並發容器以及用代碼來測試ArrayList、vector以及CopyOnWriteArrayList在100個線程向list中添加1000個數據後的比較
  • Python 這3種超方便的容器你都用過嗎?
    原來,python還有這麼多強大的內置容器!Collections模塊是python的內置模塊之一,提供了很多容器類型。按照官方文檔介紹,它被用作是對python通用內置類型(list、dict、set、tuple)的一個替代。
  • 「原創」Java並發編程系列28|Copy-On-Write容器
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫正文前面兩篇講了並發編程中線程安全HashMap:ConcurrentHashMap
  • 結合JAVA詳解鍊表、棧、隊列等數據結構
    前言其實在學習數據結構之前,我也是從來都沒了解過這門課,但是隨著工作的慢慢深入,之前學習的東西實在是不夠用,並且太皮毛了。太淺,只是懂得一些淺層的,我知道這個東西怎麼用,但是要優化、或者是解析,就不知道該咋弄了。
  • 跟我學C++中級篇——STL的學習
    另外在此基礎上,還要提醒同學們的是,除了上面的庫,在各個平臺的開發廠商中,還會針對實際情況,對標準庫進行擴展,這些可以歸納為擴展庫。同時,隨著c++標準的不斷迭代,還推出了很多新的庫,同學們需要不斷的學習跟進,目前最新的c++標準為c++20。