為什么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();
}
}
棧的最基本的特征是 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
- 鏈表比數組花費更多空間
- 鏈表的隨機訪問性質比數組差(雖然這個對棧來說問題不大)
- 鏈表的每次插入和刪除都涉及到一個節點對象的創建和棄用,非常低效和浪費空間,而動態數組幾乎是0花費的(數組充滿時重新拷貝除外)
- 鏈表是非連續的,訪問時候不能充分利用cpu cache
個人覺得第三點最重要
所以無論是棧還是隊列,JDK都是建議使用ArrayDeque而不是LinkedList實現,ArrayDeque比較復雜的一點就是需要指定初始大小,當然你不指定也行。但是它的效率確實是比LinkedList高的