Java集合—PriorityQueue
PriorityQueue基本特点
- 是数组实现来存放数据的
- 优先级队列大小不受限制,可以再创建时指定大小,
队列也能自动扩容(小 2倍,队列大(大于64)按照1.5倍 扩容) - 此队列是不能存储null值,也不支持不可比较的对象
- 优先级的队列是基于自然排序或者Compartor自定义排序规则来进行数据优先级处理
PriorityQueue底层源码实现
- 类的继承关系
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
继承自AbstractQueue,Collection接口中的部分方法在PriorityQueue中进行实现
- 类的构造函数
1.无参数构造函数:默认参数值为11
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
2.有参数构造函数:自定义参数值
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
- 主要方法分析
1.add()方法:添加元素
public boolean add(E e) {
return offer(e);
}
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
//存储的数据不能为null
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 grow(int minCapacity) {
int oldCapacity = queue.length;
// Double size if small; else grow by 50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) :
(oldCapacity >> 1));
//当容量小于64,按照2倍扩容,否则按照1.5倍扩容
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
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;
//k表示size,即最后位置
while (k > 0) {
//通过k找到父节点
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (key.compareTo((E) e) >= 0)
//key大于e,即新节点大于父节点
break;
//若孩子节点小于父节点,将父节点的值插入到孩子节位置
queue[k] = e;
将k指向父节点
k = parent;
}
queue[k] = key;
}
添加元素过程注意:
1.扩容问题(当容量小于64,按照2倍扩容,否则按照1.5倍扩容)
2.添加的元素值不能为null,要先进行判断
2.peek()方法:获取优先级队列头结点
public E peek() {
return (size == 0) ? null : (E) queue[0];
}
获取优先级队列头元素,即获取优先级队列中值最小的元素
3.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) // 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;
}
删除节点过程注意:如果待删除节点位置为队尾,则直接将队尾位置设为null
4.删除堆顶元素
public E poll() {
if (size == 0)
return null;
int s = --size;
modCount++;
//获取堆顶元素,即要删除的元素
E result = (E) queue[0];
//获取队列最后一个元素,要插入堆顶位置
E x = (E) queue[s];
//将队尾位置设为null
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);
}
private void siftDownComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>)x;
//获取到堆容量一半的位置
int half = size >>> 1; // loop while a non-leaf
//从根节点调整到half位置结束
while (k < half) {
//找到当前节点的左孩子
int child = (k << 1) + 1; // assume left child is least
Object c = queue[child];
//右孩子
int right = child + 1;
//找到k节点的左右孩子中最小的孩子节点
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指向最小的孩子节点
k = child;
}
queue[k] = key;
}