PriorityQueue是Java util包里的具有“优先级”特征的队列,其接受类需要实现Compara接口。PriorityQueue可以当作小顶堆使用(不实现任何Comparable接口,将会按照自然排序(nature odering排序)。
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
//序列化识别id
private static final long serialVersionUID = -7720805057305804111L;
//默认的容量是11
private static final int DEFAULT_INITIAL_CAPACITY = 11;
//数组实现
transient Object[] queue;
//大小
private int size = 0;
//比较器(默认为自然比较)
private final Comparator<? super E> comparator;
//
transient int modCount = 0;
//常用方法
PriorityQueue();
PriorityQueue(int initialCapacity);
PriorityQueue(Comparator<? super E> comparator);
PriorityQueue(int initialCapacity,Comparator<? super E> comparator);
PriorityQueue(Collection<? extends E> c);
grow(int minCapacity);
//添加
public boolean add(E e) {
return offer(e);
}
//取堆顶
public E peek() {
return (size == 0) ? null : (E) queue[0];
}
//删除
public boolean remove(Object o) {
int i = indexOf(o);
if (i == -1)
return false;
else {
removeAt(i);
return true;
}
}
//contains,顺序查找
public boolean contains(Object o) {
return indexOf(o) != -1;
}
//poll
poll();
}
解析:
1. grow函数用于增加容量(如果容量小于64就双倍容量,大于64就增加50%)
1. add(E e)
public boolean add(E e) {
return offer(e);
}
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;
}
解析:
1. add函数调用了offer
2. offer函数首先检查了是否超过容量,如果超过容量就调用grow函数增加容量
3. 然后调用siftUp函数插入元素
4. 插入的主要逻辑就是 把整个Object数组当作是小顶堆(完全二叉树),具体逻辑看代码注释
2. remove(Object o)
删除元素同时为了保持整个小顶堆,需要做调整
public boolean remove(Object o) {
int i = indexOf(o); //顺序查找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) // removed last element
queue[i] = null;
else {
E moved = (E) queue[s];//取出最后一个元素
queue[s] = null;
siftDown(i, moved);
if (queue[i] == moved) {
siftUp(i, moved);
if (queue[i] != moved)
return moved;
}
}
return null;
}
1.删除元素时,首先查找元素的位置,调用removeAt删除元素
2.将最后一个元素取出,然后置空,调整小顶堆
/**
* Inserts item x at position k, maintaining heap invariant by
* promoting x up the tree until it is greater than or equal to
* its parent, or is the root.
*
* To simplify and speed up coercions and comparisons. the
* Comparable and Comparator versions are separated into different
* methods that are otherwise identical. (Similarly for siftDown.)
*
* @param k the position to fill
* @param x the item to insert
//在k处插入元素,并向上调整堆至小顶堆
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
@SuppressWarnings("unchecked")
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];
if (key.compareTo((E) e) >= 0) //如果大于等于当前节点,break
break;
queue[k] = e; //如果小于,将父亲节点移到当前位置
k = parent;//继续查看父亲节点
}
queue[k] = key;
}
@SuppressWarnings("unchecked")
//同上,区别是使用了用户自定义
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;
}
/**
* Inserts item x at position k, maintaining heap invariant by
* demoting x down the tree repeatedly until it is less than or
* equal to its children or is a leaf.
*
* @param k the position to fill
* @param x the item to insert
*/
//在k处插入x,向下调整小顶堆
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x); //使用用户定义比较器
else
siftDownComparable(k, x); //使用默认比较器
}
@SuppressWarnings("unchecked")
private void siftDownComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>)x;
int half = size >>> 1; // loop while a non-leaf 从非叶子节点开始,叶子节点只用向上调整就行
while (k < half) {
int child = (k << 1) + 1; // assume left child is least
Object c = queue[child]; //位置k的左孩子
int right = child + 1;
if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0) //左孩子比右孩子大
c = queue[child = right]; //位置k的右孩子
if (key.compareTo((E) c) <= 0)
break;//如果key小于孩子中比较小的那个
queue[k] = c; //交换到k较小的孩子中继续比较,一直到叶子节点
k = child;
}
queue[k] = key;
}
@SuppressWarnings("unchecked")
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;
}
3. poll()
取出最小值,并向下调整小顶堆
@SuppressWarnings("unchecked")
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;
}