1、LinkedList
有人可能会问,这货怎么还是个Queue?
实际上LinkedList不仅实现了List,还实现了Deque,而Deque继承自Queue。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
我们知道队列的特性,先进先出,而Deque定义为双端队列,即队首队尾都有出入口,可以实现双端出入。
操作就不看了,很简单的链表操作。
2、PriorityQueue
看名字就知道,这是一个有优先级的队列,我们来看看它的内部定义:
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
//默认容量
private static final int DEFAULT_INITIAL_CAPACITY = 11;
/**
* Priority queue represented as a balanced binary heap: the two
* children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
* priority queue is ordered by comparator, or by the elements'
* natural ordering, if comparator is null: For each node n in the
* heap and each descendant d of n, n <= d. The element with the
* lowest value is in queue[0], assuming the queue is nonempty.
*/
transient Object[] queue; // 用数组保存元素
int size;
private final Comparator<? super E> comparator;
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, 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;
}
...省略其他代码
}
从上面我们可以知道,这是一个平衡二叉树结构的队列,且其父节点都比叶子节点小,类似下图结构
而且我们根据上图可以得到如下结论:
- 左子节点的下标 = 父节点下标*2+1
- 右子节点的下标 = 父节点下标*2+2
- 父节点下标 = (子节点-1)/2
来看一下它的入队操作:
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1); //扩容,长度小于64为原来的两倍,反之为原来的150%
siftUp(i, e);
size = i + 1;
return true;
}
private void siftUp(int k, E x) {
if (comparator != null) //比较器为空
siftUpUsingComparator(k, x, queue, comparator); //对比用了comparator,其他和siftUpComparable一致
else
siftUpComparable(k, x, queue);
}
private static <T> void siftUpComparable(int k, T x, Object[] es) {
Comparable<? super T> key = (Comparable<? super T>) x;
while (k > 0) {
int parent = (k - 1) >>> 1; //找到其父节点下标
Object e = es[parent];
if (key.compareTo((T) e) >= 0) //对比,大于就结束
break;
es[k] = e; //把父元素往下移
k = parent; //继续同上对比
}
es[k] = key;
}
出队操作有两种,一种是移除数根元素,一种是移除任意位置元素,都涉及到元素移动的操作
详情请移步https://www.cnblogs.com/CarpenterLee/p/5488070.html
3、ArrayDeque
内部使用循环数组来实现双端队列,分别定义了head和tail用于指向队首队尾在数组中的下标。
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable{
transient Object[] elements; //存储元素
transient int head; //队首下标
transient int tail; //队尾下标
}
其中有两个很重要的方法,涉及到头尾下标的移动,入队出队的操作就是依赖这两个方法来移动头尾下标
/**
* Circularly increments i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int inc(int i, int modulus) { //循环递增
if (++i >= modulus) i = 0; //大于数组长度就归零
return i;
}
/**
* Circularly decrements i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int dec(int i, int modulus) { //循环递减
if (--i < 0) i = modulus - 1; //小于零就设置为数组最后一位
return i;
}
ArrayDeque也有两种迭代器实现,分别按队列的两端顺序遍历
public Iterator<E> iterator() {
return new DeqIterator();
}
public Iterator<E> descendingIterator() {
return new DescendingIterator();
}