這篇文章來自我的部落格
正文之前
在上一篇文章中已經講述了連結串列基於列表的基本用法,所以,這一篇文章要講述連結串列基於佇列的基本用法
主要內容
- 基本概念
- 基於單向佇列的操作
- 基於雙向佇列的操作
正文
1. 基本概念
既然是基於佇列的操作,就要介紹一下佇列的概念:
單向佇列(Queue)是先進先出(First-In-First-Out)的線性結構,就好比我們生活中的排隊,先來排隊的人先辦理事務,佇列只支援在隊尾新增元素,在隊首刪除元素
雙向佇列(Deque,double-ended queue),也叫做雙端佇列,是基於佇列和棧的結構,可以在佇列兩邊進行新增和刪除操作
在連結串列中使用基於佇列的方法時,其實是呼叫上一篇文章中定義的方法,只不過在不同的位置使用來達到模擬的效果
2. 基於單向佇列的操作
主要內容:
- 新增節點 offer()
- 刪除節點
poll() remove()- 查詢元素 peek() element()
在這幾個基本的操作中,新增和刪除是針對節點而言,而查詢雖然是針對節點,但是查詢的結果是返回節點中的元素的
1. 新增節點
使用add(),在add()中又有linkLast(),結果就是在末尾新增節點:
/**
* Adds the specified element as the tail (last element) of this list.
*
* @param e the element to add
* @return {@code true} (as specified by {@link Queue#offer})
* @since 1.5
*/
public boolean offer(E e) {
return add(e);
}
複製程式碼
2. 刪除節點
刪除元素有兩種方法,區別就是,一個先判斷元素是否為null,而另一個不進行判斷:
- poll()
先判斷元素是否存在,然後呼叫unlinkFirst(),刪除第一個節點:
/**
* Retrieves and removes the head (first element) of this list.
*
* @return the head of this list, or {@code null} if this list is empty
* @since 1.5
*/
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
複製程式碼
- remove()
呼叫removeFirst(),最終也是呼叫unlinkFirst(),刪除第一個節點:
/**
* Retrieves and removes the head (first element) of this list.
*
* @return the head of this list
* @throws NoSuchElementException if this list is empty
* @since 1.5
*/
public E remove() {
return removeFirst();
}
複製程式碼
3. 修改元素
在基於佇列的操作中是沒有修改元素的方法的,不管是單向還是雙向佇列:
4. 查詢元素
- peek()
先檢查節點是否為空,若不為空就返回第一個節點的元素:
/**
* Retrieves, but does not remove, the head (first element) of this list.
*
* @return the head of this list, or {@code null} if this list is empty
* @since 1.5
*/
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
複製程式碼
- element()
直接返回第一個節點的元素,可能會丟擲異常:
/**
* Retrieves, but does not remove, the head (first element) of this list.
*
* @return the head of this list
* @throws NoSuchElementException if this list is empty
* @since 1.5
*/
public E element() {
return getFirst();
}
複製程式碼
3. 基於雙向佇列的操作
主要內容:
- 新增節點 offerFirst() offerLast() push()
- 刪除節點 pollFirst() pollLast() pop() removeFirstOccurrence() removeLastOccurrence()
- 查詢元素 peekFirst() peekLast()
1. 新增節點
- 新增節點至隊首
呼叫addFirst(),然後是linkFirst(),新增節點至隊首:
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
複製程式碼
- 新增節點至隊尾
和上述一樣,都是連著再次呼叫其他方法來達到效果:
public boolean offerLast(E e) {
addLast(e);
return true;
}
複製程式碼
- 模擬棧操作的新增一個節點至隊首,最終還是呼叫linkFirst():
public void push(E e) {
addFirst(e);
}
複製程式碼
2. 刪除節點
- 刪除第一個節點,呼叫unlinkFirst():
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
複製程式碼
- 刪除最後一個節點, 呼叫unlinkLast():
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
複製程式碼
- 模擬棧操作的刪除第一個節點,最終還是呼叫unlinkFirst():
public E pop() {
return removeFirst();
}
複製程式碼
- 刪除某個節點的元素,在它第一次出現的位置
remove()方法是從隊首還是進行遍歷,如果找到與指定元素相同的節點元素,就返回,所以是在元素第一次出現的位置將其刪除:
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}
複製程式碼
- 刪除某個節點的元素,在它最後一次出現的位置
其實這個方法的寫法和remove()是類似的,只不過是從隊尾開始遍歷:
public boolean removeLastOccurrence(Object o) {
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
複製程式碼
3. 查詢元素
- 得到隊首、隊尾的節點的元素
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
複製程式碼
這一篇文章就結束了,接下來會是迭代器的分析,作為連結串列系列文章的最後一篇,然後會有一個關於ArrayList和LinkedList的對比分析