目录
ArrayDeque
特点
底层数据结构:数组。
Collection接口下:存储单值。
继承的接口
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable
- Deque:双端队列接口。
- Cloneable:可以使用clone方法。
- Serializable:可序列化。
双端队列可以实现普通队列和栈的功能。
使用
双端队列
添加和删除元素分别都可以从头部和尾部进行。
- 添加元素
addFirst(E e) //头插,如果e为空返回异常
offerFirst(E e) //头插并返回是否添加成功,如果e为空返回异常
addLast(E e) //尾插,如果e为空返回异常
offerLast(E e) //尾插并返回是否添加成功,如果e为空返回异常
- 删除元素
removeFirst() //头删,并返回删除元素的值,如果为空则抛出异常
pollFirst() //头删,并返回删除元素的值,如果为空则返回null
removeLast() //尾删,并返回删除元素的值,如果为空则抛出异常
pollLast()//尾删,并返回删除元素的值,如果为空则返回null
removeFirstOccurrence(Object o) //删除第一次出现的指定元素
removeLastOccurrence(Object o) //删除最后一次出现的指定元素
- 获取元素
getFirst() //获取第一个元素,如果为空则抛出异常
getLast() //获取最后一个元素,如果为空则抛出异常
双端队列作普通队列
add(E e) //尾插
offer(E e) //尾插并返回是否成功
remove() //头删,并返回删除元素的值,如果为空则抛出异常,底层调用的是removeFirst()
poll() //头删,并返回删除元素的值,如果为空则返回null,底层调用的是pollFirst()
element() //获取第一个元素,如果为空则抛出异常
peek() //获取最后一个元素,如果为空则抛出异常
双端队列作栈
push(E e) //栈顶添加一个元素
pop() //移除栈顶元素,如果为空则抛出异常
其他
size() //获取元素个数
isEmpty() //判断队列是否为空
iterator() //迭代器,从前向后迭代
descendingIterator() //迭代器,从后向前迭代
contain(Object o) //判断队列中是否存在该元素
toArray() //转成数组
clear() //清空队列、
clone() //克隆一个新的队列
源码分析
构造器
public ArrayDeque() {
elements = (E[]) new Object[16];//默认容量为16
}
public ArrayDeque(int numElements) {
allocateElements(numElements);//将容量向上取2的幂
}
public ArrayDeque(Collection<? extends E> c) {
allocateElements(c.size());
addAll(c);
}
add相关
其他添加方法都调用这两个函数
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
//队头添加,比(head-1)%elemrnts.length效率更高
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail)
doubleCapacity();
}
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
elements[tail] = e;
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}
doubleCapacity方法
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;//2倍扩容
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 = (E[])a;
head = 0;
tail = n;
}
示意图
poll相关
其他删除方法都调用这两个函数
public E pollFirst() {
int h = head;
E result = 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);//循环
E result = elements[t];//保存删除元素
if (result == null)
return null;
elements[t] = null;//将数组中删除元素置空
tail = t;
return result;
}
get相关
其他获取方法都调用这两个函数
public E getFirst() {
E x = elements[head];
if (x == null)
throw new NoSuchElementException();
return x;
}
public E getLast() {
E x = elements[(tail - 1) & (elements.length - 1)];
if (x == null)
throw new NoSuchElementException();
return x;
}
LinkedList
特点
LinkedList可作双端队列使用。效率没有ArrayDeque高。
继承的接口
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
Deque:可作双端队列使用,添加/删除元素都可以从头部或者尾部进行。
使用
当作链表操作
//添加
add(E e); //尾插
add(int index, E element); //随机插入
//删除
remove(E o); //删除指定元素
remove(int index) //删除指定下标元素
//获取
get(int index); //获取指定下标元素
//修改
set(int index , E element); //修改指定下标元素
作双端队列使用
//添加
addFirst(E e); //头插,特有方法
addLast(E e); //尾插,特有方法
offerFirst(E e); //头插,返回是否成功
offerLast(E e); //尾插,并返回是否成功
//删除
removeFirst(E e); //头删并获取
removeLast(E e); //尾删并获取
pollFirst(); //头删
pollLast(); //尾删
removeFirstOccurrence(Object o); //删除第一次出现的指定元素
removeLastOccurrence(Object o); //删除最后一次出现的指定元素
//获取
getFirst(); //获取第一个元素,为空则抛异常
getLast(); //获取最后一个元素,为空则抛异常
peekFirst(): //获取第一个元素,为空则返回空
peekLast(); //获取最后一个元素,为空则返回空
作普通队列使用
add(E e) //尾插
offer(E e) //尾插并返回是否成功
remove() //头删,并返回删除元素的值,如果为空则抛出异常,底层调用的是removeFirst()
poll() //头删,并返回删除元素的值,如果为空则返回null,底层调用的是pollFirst()
element() //获取第一个元素,如果为空则抛出异常
peek() //获取最后一个元素,如果为空则抛出异常
作栈使用
push(E e) //栈顶添加一个元素
pop() //移除栈顶元素,如果为空则抛出异常
其他
size() //获取元素个数
iterator() //迭代器,从前向后迭代
contain(Object o) //判断队列中是否存在该元素
toArray() //转成数组
clear() //清空队列
clone() //克隆一个新的队列
源码分析
略
PriorityQueue
特点
传统队列具有先入先出的特点,先添加的元素先弹出,先添加的元素优先级高。
优先级队列的先入先出:提供一个优先级比较原则,优先级队列根据这个原则,谁最小优先级最高,优先级高的先弹出。
继承的接口
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
- Queue:队列接口,具有队列先入先出的特点。
- Serializable:可序列化。
- Iterator:迭代器,可以从前向后遍历。
使用
常用方法
//添加一个指定元素,如果e为空则返回空指针异常
boolean offer(E e)
//添加一个指定元素,直接调用offer方法
boolean add()
//删除一个指定元素,如果e为空则返回false
boolean remove(Object o)
//删除队头,如果没有队头则返回null
E poll()
//获取队头元素,如果没有队头则返回null
E peek()
//获取队头元素,如果没有队头则抛出异常
E element()
源码分析
构造器
//无参构造,默认容量为11
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
//有参构造指定初始容量
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
//双参构造,初始容量和外比较器
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
//有参构造,外比较器
@SuppressWarnings("unchecked")
public PriorityQueue(Collection<? extends E> c) {
if (c instanceof SortedSet<?>) {
SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
this.comparator = (Comparator<? super E>) ss.comparator();
initElementsFromCollection(ss);
}
else if (c instanceof PriorityQueue<?>) {
PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
this.comparator = (Comparator<? super E>) pq.comparator();
initFromPriorityQueue(pq);
}
else {
this.comparator = null;
initFromCollection(c);
}
}
offer方法
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;
}
siftUp方法
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
//外比较器为空时使用内比较器
else
siftUpComparable(k, x);
}
private void siftUpComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;//找到父节点,无符号右移
Object e = queue[parent];
//如果x比父节点大,满足小根堆,退出循环
if (key.compareTo((E) e) >= 0)
break;
//父节点下移
queue[k] = e;
//更新父节点
k = parent;
}
queue[k] = key;//最后放入要插入的元素
}
//同上,只是比较方法不同
private void siftUpUsingComparator(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}
grow方法
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// 如果初始容量小于6,2倍+2扩容,否则1.5倍扩容
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;
}
poll方法
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;
}
siftDown
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
//外比较器为空时使用内比较器
else
siftDownComparable(k, x);
}
private void siftDownComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super 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 &&
((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
c = queue[child = right];
//如果孩子比根大,退出
if (key.compareTo((E) c) <= 0)
break;
//孩子上移
queue[k] = c;
k = child;
}
queue[k] = key;
}
//同上,只是比较方法不同
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;
queue[k] = c;
k = child;
}
queue[k] = x;
}
remove方法
public boolean remove(Object o) {
int i = indexOf(o);//找出该元素下标
if (i == -1)
return false;
else {
removeAt(i);
return true;
}
}
private E removeAt(int i) {
assert i >= 0 && i < size;
modCount++;
int s = --size;
if (s == i) // 移除最后一个节点
queue[i] = null;
else {
E moved = (E) queue[s];// 记录最后一个元素
queue[s] = null;// 将最后一个元素置空
siftDown(i, moved); // 将最后一个元素放在i的位置,向下调整
//向下调整如果执行,那么此时i位置一定比当前子树的根小,满足小根堆
//如果向下调整没有执行,则向上调整
//因为当左右分支差距过大时,无法确定最后一个节点是否比当前子树的根小
if (queue[i] == moved) {
siftUp(i, moved);//向上调整
if (queue[i] != moved)
return moved;
}
}
return null;
}