資料結構(四)佇列
阿新 • • 發佈:2018-11-21
一、基本概念
1、特點:
- 在佇列頭部進行刪除,在佇列的尾部進行插入操作
2、主要實現:
- 使用迴圈陣列
- 使用連結串列
3、關係圖:
二、Queue
public interface Queue<E> extends Collection<E> { //新增 boolean add(E var1); //新增 boolean offer(E var1); //移除 E remove(); //移除 E poll(); //獲取元素 E element(); //獲取 E peek(); }
一般peek、poll、offer方法跟其他類似方法的區別在於為空會返回null
三、Deque
1、特點:
- 雙端佇列:Deque是一種具有佇列和棧的性質的資料結構,插入和刪除操作可以在表的兩端進行。
LinkedList實現了Deque介面,可以在兩端進行插入和刪除操作。
2、介面原始碼:
public interface Deque<E> extends Queue<E> { //將元素插入佇列 boolean add(E e); //將元素插入佇列,與add相比,在容量受限時應該使用這個 boolean offer(E e); //將隊首的元素刪除,佇列為空則丟擲異常 E remove(); //將隊首的元素刪除,佇列為空則返回null E poll(); //獲取隊首元素,但不移除,佇列為空則丟擲異常 E element(); //獲取隊首元素,但不移除,佇列為空則返回null E peek(); ... }
提供了在兩端移除、新增的相關方法
四、ArrayDeque
雙端佇列
- ArrayDeque通過迴圈陣列的方式實現迴圈佇列,容量為2的次冪。
- 作為Stack,因為其非執行緒安全所以效率高於java.util.Stack,而作為佇列,因為其不需要結點支援所以更快。
1、變數:
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable { //元素儲存為陣列 transient Object[] elements; //頭部元素索引 transient int head; //隊部元素索引 transient int tail; //最小容量 private static final int MIN_INITIAL_CAPACITY = 8; ... }
2、構造:
/**
* 無參構造,預設大小為16
*/
public ArrayDeque() {
elements = new Object[16];
}
/**
* @param numElements 初始容量
*/
public ArrayDeque(int numElements) {
allocateElements(numElements);
}
/**
* 傳入一個集合
* @param c
*/
public ArrayDeque(Collection<? extends E> c) {
//獲取初始容量,並建立陣列
allocateElements(c.size());
//新增元素
addAll(c);
}
獲取初始容量,並建立陣列
private void allocateElements(int numElements) {
int initialCapacity = MIN_INITIAL_CAPACITY;
//如果傳入的容量>=MIN_INITIAL_CAPACITY
if (numElements >= initialCapacity) {
//通過右移和位或運算得到大於numElements的2^n個容量
initialCapacity = numElements;
initialCapacity |= (initialCapacity >>> 1);
initialCapacity |= (initialCapacity >>> 2);
initialCapacity |= (initialCapacity >>> 4);
initialCapacity |= (initialCapacity >>> 8);
initialCapacity |= (initialCapacity >>> 16);
initialCapacity++;
if (initialCapacity < 0) // Too many elements, must back off
initialCapacity >>>= 1; // Good luck allocating 2^30 elements
}
elements = new Object[initialCapacity];
}
3、新增元素
新增元素都是從佇列的尾部新增,如果呼叫addFirst,就是將索引為0作為隊首,需要從length-1的位置(隊尾)開始新增。如果addLast,則索引為0作為隊尾。
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
//如果elements.length為8,最終head的索引為7,然後賦值
elements[head = (head - 1) & (elements.length - 1)] = e;
//進行擴容
if (head == tail)
doubleCapacity();
}
//如果將1-8的元素依次通過addFirst新增到佇列中,此時head是從7到0,最終的順序為[8,7,6,5,4,3,2,1]。
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
//隊尾賦值,首次新增元素時tail為0
elements[tail] = e;
//將tail後移一位
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}
//如果將1-8的元素依次通過addLast新增到佇列中,此時tail從1到8,最終的順序為[1,2,3,4,5,6,7,8]
//將容量擴大到2倍,然後元素複製到新陣列
private void doubleCapacity() {
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p; // number of elements to the right of p
int newCapacity = n << 1;
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
Object[] a = new Object[newCapacity];
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);
elements = a;
head = 0;
tail = n;
}
4、刪除元素:
刪除元素時在隊首刪除,removeFirst時隊首在前(索引為head)開始刪,removeLast時隊首在後(索引為tail)處開始刪。
public E removeFirst() {
E x = pollFirst();
if (x == null)
throw new NoSuchElementException();
return x;
}
public E removeLast() {
E x = pollLast();
if (x == null)
throw new NoSuchElementException();
return x;
}
public E pollFirst() {
final Object[] elements = this.elements;
final int h = head;
@SuppressWarnings("unchecked")
//獲取head元素
E result = (E) elements[h];
// Element is null if deque empty
if (result != null) {
//head的元素置空,將head向後移動一位
elements[h] = null; // Must null out slot
head = (h + 1) & (elements.length - 1);
}
return result;
}
public E pollLast() {
final Object[] elements = this.elements;
//通過&運算獲取隊首元素索引(如果tail為2,隊首索引t為1)
final int t = (tail - 1) & (elements.length - 1);
@SuppressWarnings("unchecked")
E result = (E) elements[t];
if (result != null) {
//刪除最後一個元素,將tail向前移動一位
elements[t] = null;
tail = t;
}
return result;
}
5、獲取元素:
public E getFirst() {
@SuppressWarnings("unchecked")
E result = (E) elements[head];
if (result == null)
throw new NoSuchElementException();
return result;
}
public E getLast() {
@SuppressWarnings("unchecked")
E result = (E) elements[(tail - 1) & (elements.length - 1)];
if (result == null)
throw new NoSuchElementException();
return result;
}