-
Queue接口
Queue用於模擬了隊列這種數據結構,隊列通常是指“先進先出”(FIFO)的容器。隊列的頭部保存在隊列中時間最長的元素,隊列的尾部保存在隊列中時間最短的元素。新元素插入(offer)到隊列的尾部,訪問元素(poll)操作會返回隊列頭部的元素。通常,隊列不容許隨機訪問隊列中的元素。
Queue接口中定義了如下幾個方法:
-
- void add(Object e); //將指定元素加入此隊列的尾部。
- Object element(); //獲取隊列頭部的元素,但是不刪除該元素。
- boolean offer(Object e); //將指定元素加入此隊列的尾部。當使用有容量限制的隊列時,此方法通常比add(Object e)方法更好。
- Object peek(); //獲取隊列頭部的元素,但是不刪除該元素,如果此隊列為空,則返回null。
- Object poll(); //獲取隊列頭部的元素,並刪除該元素,如果此隊列為空,則返回null。
- Object remove(); //獲取隊列頭部的元素,並刪除該元素。
Queue有兩個常用的實現類:LinkedList和PriorityQueue,下面分別介紹這兩個實現類。
-
LinkedList
LinkedList類是一個比較奇怪的類,它即是List接口的實現類,這意味着它是一個List集合,可以根據索引來隨機訪問集合中的元素。除此之外,LinkedList還實現了Deque接口,Deque接口是Queue接口的子接口,它代表一個雙向隊列,Deque接口里定義了一些可以雙向操作隊列的方法:
-
- void addFirst(Object e); //將指定元素插入該雙向隊列的開頭。
- void addLast(Object e); //將指定元素插入該雙向隊列的末尾。
- Iterator descendingIterator(); //返回以該雙向隊列對應的迭代器,該迭代器將以逆向順序來迭代隊列中的元素。
- Object getFirst(); //獲取、但不刪除雙向隊列的第一個元素。
- Object getLast(); //獲取、但不刪除雙向隊列的最后一個元素。
- boolean offerFirst(Object e);//將指定元素插入該雙向隊列的開頭
- boolean offerLast(Object e);//將指定元素插入該雙向隊列的結尾
- Object peekFirst(); //獲取、但不刪除雙向隊列的第一個元素;如果此雙端隊列為空,則返回null。
- Object peekLast(); //獲取、但不刪除該雙向隊列的最后一個元素;如果此雙端隊列為空,則返回null。
- Object pollFirst(); //獲取、並刪除雙向隊列的第一個元素;如果此雙端隊列為空,則返回null。
- Object pollLast(); //獲取、並刪除雙向隊列的最后一個元素,如果此雙端隊列為空,則返回null。
- Object pop(); //pop出該雙向隊列所表示的棧中第一個元素。
- void push(Object e); //將一個元素push進該雙向隊列所表示的棧中。
- Object removeFirst(); //獲取、並刪除該雙向隊列的第一個元素。
- Object removeFirstOccurrence(Object e); //刪除該雙向隊列的第一次的出現元素e。
- removeLast(); //獲取、並刪除該雙向隊列的最后一個元素。
- removeLastOccurrence(Object e); //刪除該雙向隊列的最后一次的出現元素e
從以上方法可以看出,LinkedList不僅可以當成雙向隊列使用,也可以當成“棧”使用,因為該類還包含了pop(出棧)和push(入棧)兩個方法。除此之外,LinkedList實現了List接口,所以還被當成List使用。
*建議:
- 如果需要遍歷List集合元素,對於ArrayList、Vector集合,則應該使用隨機訪問方法(get)來遍歷集合元素,這樣性能更好,對於LinkedList集合,則應該采用迭代器(Iterater)來遍歷集合元素。
- 如果需要經常執行插入、刪除操作來改變List集合大小,則應該使用LinkedList集合,而不是ArrayList。使用ArrayList、Vector集合將需要經常重新分配內存數組的大小,其時間開銷往往是使用LinkedList時時間開銷的幾十倍,效果很差。
- 如果有多條線程需要同時訪問List集合中的元素,可以考慮使用Vector這個同步實現。
-
PriorityQueue實現類
PriorityQueue是一個比較標准的隊列實現類,之所以說它是比較標准的隊列實現,而不是絕對標准的隊列實現是因為:PriorityQueue保存隊列元素的順序並不是按加入隊列的順序,而是按隊列元素的大小進行重新排序。因此當調用peek方法活着pull方法來取出隊列中的元素時,並不是取出最先進入隊列的元素,而是取出隊列中最小的元素。從這個意義上看,PriorityQueue已經違反了隊列的最基本原則:先進先出(FIFO)。下面程序示范了PriorityQueue隊列的用法。
public class Test { public static void main(String[] args){ PriorityQueue<Integer> pq = new PriorityQueue<Integer>(); pq.offer(3); pq.offer(-6); pq.offer(9); //打印結果為[-6, 3, 9] System.out.println(pq); //打印結果為-6 System.out.println(pq.peek()); //打印結果為-6 System.out.println(pq.poll()); } }
PriorityQueue不允許插入null元素,它還需要對隊列元素進行排序,隊列元素有兩種排序方式:自然排序、定制排序; 關於使用自然排序和定制排序與前面講到的TreeSet集合一樣,讀者可以查看Java集合(二)這章的內容