Queue
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队首。
和栈一样,队列也有两种实现方式,数组和链表
PriorityQueue
优先级队列,通过构造堆结构使最大(最小)元素先出队,使用数组进行存储;详解
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {
// 默认容量11
private static final int DEFAULT_INITIAL_CAPACITY = 11;
// 队列元素,数组集合
transient Object[] queue;
private int size = 0;
// 比较策略
private final Comparator<? super E> comparator;
// 默认构造方法
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
public PriorityQueue(Comparator<? super E> comparator) {
this(DEFAULT_INITIAL_CAPACITY, comparator);
}
public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
}
入队
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1); // 扩容
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e); // 有序入队
return true;
}
// 构造最小(大)堆,保证堆顶元素最小(大)
private void siftUp(int k, E x) {
if (comparator != null) // 不同的比较策略
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
// 通过比较(利用堆的特性)把元素x 放到数组的指定位置
private void siftUpUsingComparator(int k, E x) {
while (k > 0) {
// 无符号右移,相当于 除以2,目的: 通过构建最小堆,把最小值放到0位置
int parent = (k - 1) >>> 1; // 父结点
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)
break;
queue[k] = e; // x如果比位置k的元素小,后移
k = parent;
}
// 构建最小堆,把x放入堆中,保证顶点元素最小
queue[k] = x;
}
扩容
// 扩容
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// < 64 扩容翻倍 + 2,否则扩容50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1));
// 检查是否溢出
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity); // 计算扩容需要的容量
// 通过复制算法把原数据复制到新队列
queue = Arrays.copyOf(queue, newCapacity);
}
// 计算扩容需要的容量
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
出队
实际上就是把堆顶的元素移除,然后通过堆的特性重新选出堆顶
public E poll() {
if (size == 0)
return null;
int s = --size;
modCount++;
E result = (E) queue[0]; // 堆顶元素
E x = (E) queue[s];
queue[s] = null;
if (s != 0)
siftDown(0, x); // 重新选出堆顶
return result;
}
// 重新选出堆顶
private void siftDown(int k, E x) {
if (comparator != null) // 不同的比较策略
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
// 从0开始,比较两个子结点,重新选出堆顶
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1; // 左子结点
Object c = queue[child];
int right = child + 1; // 右子结点
if (right < size && comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
// c和child是左右两个子结点中较小(大)的元素,移动到父结点
queue[k] = c;
k = child;
}
queue[k] = x;
}
取队首元素
// 取队首元素 始终是数组第0个元素
public E peek() {
return (size == 0) ? null : (E) queue[0];
}
Deque
Deque:双向队列,支持两端操作;支持先入先出和后入先出,可以同时试下栈和队列的操作;
// 双向队列接口
public interface Deque<E> extends Queue<E> {
// 头尾新增元素 无返回
void addFirst(E e);
void addLast(E e);
// 头尾元素入队 有返回
boolean offerFirst(E e)
boolean offerLast(E e);
// 头尾删除元素
E removeFirst();
E removeLast();
// 头尾元素出队
E pollFirst();
E pollLast();
// 头尾获取元素
E getFirst();
E getLast();
// 头尾查看元素
E peekFirst();
E peekLast();
}
ArrayDeque
基于数组结构实现的双向队列
// java数组实现队列接口
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable {
transient Object[] elements;// 数组元素集合,循环队列
transient int head; // head元素指针,指向数组中head的位置
transient int tail; // tail元素指针,指向数组中tail的位置
// 最小初始容量
private static final int MIN_INITIAL_CAPACITY = 8;
// 默认构造方法,构造长度为16的数组
public ArrayDeque() {
elements = new Object[16];
}
public ArrayDeque(int numElements) {
allocateElements(numElements);
}
public ArrayDeque(Collection<? extends E> c) {
allocateElements(c.size());
addAll(c);
}
// 初始化数组
private void allocateElements(int numElements) {
elements = new Object[calculateSize(numElements)];
}
// 计算容量 这段代码的逻辑是算出大于numElements的最接近的2的n次方且不小于8
private static int calculateSize(int numElements) {
int initialCapacity = MIN_INITIAL_CAPACITY;
if (numElements >= initialCapacity) {
initialCapacity = numElements;
initialCapacity |= (initialCapacity >>> 1);
initialCapacity |= (initialCapacity >>> 2);
initialCapacity |= (initialCapacity >>> 4);
initialCapacity |= (initialCapacity >>> 8);
initialCapacity |= (initialCapacity >>> 16);
initialCapacity++;
if (initialCapacity < 0)
initialCapacity >>>= 1;
}
return initialCapacity;
}
}
入队
// 队首新增元素
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
// head - 1 左移一位
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail) // head tail相遇,说明数组已满
doubleCapacity(); // 扩容
}
// 队尾新增元素
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
elements[tail] = e;
// tail + 1 右移一位
if ( (tail = (tail + 1) & (elements.length - 1)) == head) // head tail相遇,说明数组已满
doubleCapacity();// 扩容
}
扩容
// 扩容
private void doubleCapacity() {
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p; // 头指针到数组末尾的元素个数
int newCapacity = n << 1; // 扩容1倍
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
// 创建新数组
Object[] a = new Object[newCapacity];
// 复制 head到数组末尾的元素
System.arraycopy(elements, p, a, 0, r);
// 复制 0~head-1的元素
System.arraycopy(elements, 0, a, r, p);
elements = a;
head = 0;
tail = n;
}
出队
// 从队列头出队
public E pollFirst() {
int h = head;
@SuppressWarnings("unchecked")
// 取队列头元素
E result = (E) elements[h];
// 队列头为空
if (result == null)
return null;
elements[h] = null; // 出队,把队头赋值为空
// 队列头指针右移一位
head = (h + 1) & (elements.length - 1);
return result;
}
// 从队列尾出队
public E pollLast() {
// 队列尾指针左移一位
int t = (tail - 1) & (elements.length - 1);
@SuppressWarnings("unchecked")
E result = (E) elements[t];
// 队列尾为空
if (result == null)
return null;
elements[t] = null; // 出队,把队尾赋值为空
tail = t;
return result;
}
取队首元素
// 取队首元素 head指针的位置
public E peekFirst() {
return (E) elements[head];
}
// 取队尾元素 tail指针左移一位的位置
@SuppressWarnings("unchecked")
public E peekLast() {
return (E) elements[(tail - 1) & (elements.length - 1)];
}
栈
入栈和出栈都在 队列头执行
// 入栈
public void push(E e) {
addFirst(e);
}
// 出栈
public E pop() {
return removeFirst();
}
LinkedList
链表实现队列
// java链表实现队列
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
transient int size = 0;// 队列大小
transient Node<E> first;// 头结点
transient Node<E> last;// 尾结点
// 内部类,双向链表的Node结点
private static class Node<E> {
E item;
Node<E> next; // 后驱指针
Node<E> prev; // 前驱指针
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
// 构造方法
public LinkedList() {
}
// Collection 构造方法
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
// 插入新结点First
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f); // 根据元素e构建新结点
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
// 移除头结点
private E unlinkFirst(Node<E> f) {
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
}
入队
// 队首新增结点
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);// 根据元素e构建新结点
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
// 队尾新增结点
public boolean offerLast(E e) {
addLast(e);
return true;
}
public void addLast(E e) {
linkLast(e);
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);// 根据元素e构建新结点
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
出队
// 从队列头出队
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next; // 把first指针指向first的next结点
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
// 从队列尾出队
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev; // 把last指针指向last的prev结点
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
取队首元素
// 取队首元素 first指针
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
// 取队尾元素 last指针
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
栈
入栈和出栈都在队列头执行
// 入栈
public void push(E e) {
addFirst(e);
}
// 出栈
public E pop() {
return removeFirst();
}