為什么JDK建議使用ArrayDeque而不是Stack和LinkedList實現棧和隊列


為什么JDK建議使用ArrayDeque實現棧

首先,先說為什么不建議使用Stack這個實現類:

https://www.xttblog.com/?p=3416

前面我已經寫過一篇關於 Stack(棧) 的文章了《 吃多了拉就是隊列,吃多了吐就是棧 》。鑒於網上關於 Stack 的文章眾多,但大多都是偏介紹的。並且 Stack(棧)在 Java 中廣泛存在,所以,我想再研究研究它。

我們先來看一下棧的應用吧。

  • 符號匹配
  • 中綴表達式轉換為后綴表達式
  • 計算后綴表達式
  • 實現函數的嵌套調用
  • HTML 和 XML 文件中的標簽匹配
  • 網頁瀏覽器中已訪問頁面的歷史記錄
  • Java 中的程序計數棧、堆棧

除了這些,Java 中還有非常多的地方使用到了棧。

棧是一種數據結構,所以它使用的非常普遍。面試中遇到它的可能性也比較大,所以還是很有必要掌握的。

java.util.Stack 類 Java 官方已經不在建議使用了。現在官方推薦使用 java.util.Deque。類似下面的用法:

Deque<Integer> stack = new ArrayDeque<Integer>();

那么 Java 為什么不推薦使用 Stack 呢?為什么 Stack 被廢棄了呢?

很簡單,因為 Stack 是 JDK 1.0 的產物。它繼承自 Vector,Vector 都不被推薦使用了,你說 Stack 還會被推薦嗎?

當初 JDK1.0 在開發時,可能為了快速的推出一些基本的數據結構操作,所以推出了一些比較粗糙的類。比如,Vector、Stack、Hashtable 等。這些類中的一些方法加上了 synchronized 關鍵字,容易給一些初級程序員在使用上造成一些誤解!而且在之前的幾個版本中,性能還不怎么好。

基於 Vector 實現的棧 Stack。底層實際上還是數組,所以還是存在需要擴容。Vector 是由數組實現的集合類,他包含了大量集合處理的方法。而 Stack 之所以繼承 Vector,是為了復用 Vector 中的方法,來實現進棧(push)、出棧 (pop) 等操作。這里就是 Stack 設計不好的地方,既然只是為了實現棧,不用鏈表來單獨實現,而是為了復用簡單的方法而迫使它繼承 Vector,Stack 和 Vector 本來是毫無關系的。這使得 Stack 在基於數組實現上效率受影響,另外因為繼承 Vector 類,Stack 可以復用 Vector 大量方法,這使得 Stack 在設計上不嚴謹。

基於上一篇文章中,我們對棧存在的一個基本認識,下面我們使用 LinkedList 自己實現一個棧。

package com.xttblog;
import java.util.LinkedList;
public class Stack<E> {
	LinkedList<E> list;
	public Stack(){
        list = new LinkedList();
    }
    public E pop(){
        return list.removeLast();
    }
    public void push(E o){
        list.add(o);
    }
    public E getTop(){
        return list.getLast();
    }
    public boolean isEmpty(){
        return list.size()==0;
    }
    public int size(){
        return list.size();
    }
}

img

棧的最基本的特征是 LIFO(Last In First Out),因此棧又被稱為后進先出的線性表。所以上面采用 LinkedList 實現的棧看起來也非常的簡單。雖然簡單,但我們並不需要重復的輪子。Java 提供了 Deuqe。Deque 是繼承自 Queue,而 Stack 是繼承自 Vector。Java 中的 Deuqe,即 “double ended queue” 的縮寫,是 Java 中的雙端隊列集合類型。Deque 具備普通隊列 FIFO 的功能,同時它也具備了 Stack 的 LIFO 功能,並且保留了 push 和 pop 函數,所以使用起來應該是一點障礙都沒有。

ArrayDeque 是 Deque 接口的一種具體實現,是依賴於可變數組來實現的。ArrayDeque 沒有容量限制,可根據需求自動進行擴容。ArrayDeque 可以作為棧來使用,效率要高於 Stack。ArrayDeque 也可以作為隊列來使用,效率相較於基於雙向鏈表的 LinkedList 也要更好一些。注意,ArrayDeque 不支持為 null 的元素。


之后,再說為什么建議使用ArrayDeque而不是LinkedList:

https://stackoverflow.com/questions/6163166/why-is-arraydeque-better-than-linkedlist

  1. 鏈表比數組花費更多空間
  2. 鏈表的隨機訪問性質比數組差(雖然這個對棧來說問題不大)
  3. 鏈表的每次插入和刪除都涉及到一個節點對象的創建和棄用,非常低效和浪費空間,而動態數組幾乎是0花費的(數組充滿時重新拷貝除外)
  4. 鏈表是非連續的,訪問時候不能充分利用cpu cache

個人覺得第三點最重要

所以無論是棧還是隊列,JDK都是建議使用ArrayDeque而不是LinkedList實現,ArrayDeque比較復雜的一點就是需要指定初始大小,當然你不指定也行。但是它的效率確實是比LinkedList高的


免責聲明!

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



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