java中的棧和隊列使用
在java中有寫實現好的棧和隊列提供我們使用,但是有關這些的數據結構的時候我經常性會弄錯,所以寫下來總結一下。
Stack
在java8中,Stack的官方文檔介紹如下:
public class Stack<E>
extends Vector<E>
The Stack class represents a last-in-first-out (LIFO) stack of objects.It extends class Vector with five operations that allow a vector to be treated as a stack.
The usual push and pop operations are provided, as well as a method to peek at the top item on the stack, a method to test for whether the stack is empty, and a method to search the stack for an item and discover how far it is from the top.
When a stack is first created, it contains no items.
A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class. For example:
Deque<Integer> stack = new ArrayDeque<Integer>();
大致意思為:Stack
類表示對象的后進先出(LIFO)棧。它使用五個操作擴展了Vector
類,這些操作允許將矢量視為棧。提供了通常的推入(push
)和彈出(pop
)操作,以及一種查看棧頂部的方法(peek
),一種用於測試堆棧是否為空的方法(empty
)以及一種用於在棧中搜索元素並發現其和頂部top距離的方法(search
)。從頂部開始。 首次創建堆棧時,它不包含任何項目。
除此之外Deque接口及其實現提供了一組更完整和一致的LIFO堆棧操作,應優先使用此類。例如:
Deque<Integer> stack = new ArrayDeque<Integer>();
從上面的信息我們可以得出Stack
有5個常用的方法
Modifier and Type | Method and Description |
---|---|
boolean |
empty() 測試棧是否為空 |
E |
peek() 在不將其從棧中移除的情況下,查看該棧頂部的對象。在棧為空的時候會報 EmptyStackException |
E |
pop() 刪除此棧頂部的對象,並將該對象作為此函數的值返回。在棧為空的時候會報 EmptyStackException |
E |
push(E item) 將一個項目推送到此堆棧的頂部。 |
int |
search(Object o) 返回對象在此棧上的從1開始的位置。對象不存在則會返回-1 |
我們可以可以看到Satck的功能基本上已經滿足我們的要求了,可是在文檔上依然推薦我們使用Deque
雙端隊列的實現類來完成Satck的功能,為什么是這也呢?
查了一些資料加上自己的理解是這樣認為的,java中Satck類設計的有一些問題,因為我們可以看到Satck
是繼承自 Vector
,但是依照程序設計的一個原則多組合少繼承來看,這個設計是不合理的,應該是Vector
組成Satck
比較好,然后java的官方也發現了這個問題,但是后面想更改的時候時間就比較晚了,所以才在文檔里面建議我們使用雙端隊列來模擬棧比較好
Queue
在java中Queue是一個接口。在文檔當中有對其的描述如下:
Queue除了基本的“收集”操作外,隊列還提供其他插入,提取和檢查操作。這些方法中的每一種都以兩種形式存在:一種在操作失敗時引發異常,另一種返回一個特殊值(根據操作而為null或false)。插入操作的后一種形式是專為與容量受限的Queue實現一起使用而設計的;在大多數實現中,插入操作不會失敗。
下面這個表格就對應着一個發生異常,一個返回特殊值
Throws exception | Returns special value | |
---|---|---|
Insert | add(e) |
offer(e) |
Remove | remove() |
poll() |
Examine | element() |
peek() |
對應的方法介紹
Modifier and Type | Method and Description |
---|---|
boolean |
add(E e) 如果可以立即將指定的元素插入此隊列,而不會違反容量限制,則在成功時返回true,如果當前沒有可用空間,則拋出IllegalStateException。 |
E |
element() 檢索但不刪除此隊列的頭。 |
boolean |
offer(E e) 如果可以在不違反容量限制的情況下立即將指定的元素插入此隊列。 |
E |
peek() 檢索但不刪除此隊列的頭部,如果此隊列為空,則返回null。 |
E |
poll() 檢索並刪除此隊列的頭部,如果此隊列為空,則返回null。 |
E |
remove() 檢索並刪除此隊列的頭。 |
Deque
Deque是雙端隊列的接口,也是我們使用最多的隊列,既可以當作棧也可以當作隊列使用
Deque
是支持在兩端插入和刪除元素的線性集合。名稱雙端隊列是“雙端隊列”(double ended queue)的縮寫。大多數Deque實施對它們可能包含的元素數量沒有固定的限制,但是此接口支持容量受限的雙端隊列以及沒有固定大小限制的雙端隊列。 此接口定義訪問雙端隊列兩端的元素的方法。提供了用於插入,刪除和檢查元素的方法。這些方法中的每一種都以兩種形式存在:一種在操作失敗時引發異常,另一種返回一個特殊值(根據操作而為null或false)。插入操作的后一種形式是專為容量受限的Deque實現而設計的。在大多數實現中,插入操作不會失敗。
類似於隊列,他也有一個表格
First Element (Head):
Throws exception | Returns special value | |
---|---|---|
Insert | addFirst(e) |
offerFirst(e) |
Remove | removeFirst() |
pollFirst() |
Examine | getFirst() |
peekFirst() |
Last Element (Tail)
Throws exception | Returns special value | |
---|---|---|
Insert | addLast(e) |
offerLast(e) |
Remove | removeLast() |
pollLast() |
Examine | getLast() |
peekLast() |
因為該接口擴展了Queue接口。當雙端隊列用作隊列時,將導致FIFO(先進先出)行為。元素在雙端隊列的末尾添加,並從開頭刪除。從Queue接口繼承的方法與Deque方法完全等效,如下表所示:
Queue Method |
Equivalent Deque Method |
---|---|
add(e) |
addLast(e) |
offer(e) |
offerLast(e) |
remove() |
removeFirst() |
poll() |
pollFirst() |
element() |
getFirst() |
peek() |
peekFirst() |
雙端隊列也可以用作LIFO(后進先出)堆棧。此接口應優先於舊版Stack類使用。當雙端隊列用作堆棧時,元素從雙端隊列的開頭被壓入並彈出。堆棧方法與Deque方法完全等效,如下表所示:
Stack Method | Equivalent Deque Method |
---|---|
push(e) |
addFirst(e) |
pop() |
removeFirst() |
peek() |
peekFirst() |
總結來說就是使用Deque作為隊列時主要使用隊列中的表對應提供的方法,而使用Deque作為棧時主要使用棧對應的表提供的方法。
因為Deque時繼承自Queue,所以Queue的方法本身在Deque中是起作用的,但是除此之外Deque中對應棧的方法如:push、pop也是有的,並且功能也是剛好對應
public void push(E e) {
addFirst(e);
}
public E pop() {
return removeFirst();
}
所以,總結來說想使用棧的話用Deque實現是完全沒有問題的。
另外需要說明Deque的實現類有許多,但是我們平時用不考慮多線程,使用ArrayDeque、LinkedList就足夠了
PriorityQueue
PriorityQueue
是基於優先級堆的無界優先級隊列。優先級隊列的元素根據其自然順序或在隊列構造時提供的Comparator
進行排序,具體取決於所使用的構造函數。優先級隊列不允許空元素。依賴自然順序的優先級隊列也不允許插入不可比較的對象(這樣做可能會導致ClassCastException
)。
簡單來說PriorityQueue
就是一個優先級隊列,在我們需要堆的時候可以使用PriorityQueue
當作堆進行使用,因為PriorityQueue
繼承自AbstractQueue
,而AbstractQueue
實現Queue
,所以PriorityQueue
的方法和Queue差不多,使用起來也比較方便
總結
在不考慮多線程的情況下,使用棧就是使用Deque的實現類,使用隊列就使用Deque的實現類,使用堆就使用PriorityQueue