DefaultPriorityQueue保证队列元素的顺序性,在add和poll元素时会移动元素,根据元素大小重新排列数据在元素中的位置,保证元素的顺序性。
package io.netty.util.internal;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import static io.netty.util.internal.PriorityQueueNode.INDEX_NOT_IN_QUEUE;
//一个具有优先级排序功能的队列
public final class DefaultPriorityQueue<T extends PriorityQueueNode> extends AbstractQueue<T>
implements PriorityQueue<T> {
private static final PriorityQueueNode[] EMPTY_ARRAY = new PriorityQueueNode[0];
//比较器,用来比较元素优先级(大小)
private final Comparator<T> comparator;
//存储队列中元素的数组
private T[] queue;
//队列中元素的数量
private int size;
public DefaultPriorityQueue(Comparator<T> comparator, int initialSize) {
this.comparator = ObjectUtil.checkNotNull(comparator, "comparator");
queue = (T[]) (initialSize != 0 ? new PriorityQueueNode[initialSize] : EMPTY_ARRAY);
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(Object o) {
//如果不是PriorityQueueNode类型返回false
if (!(o instanceof PriorityQueueNode)) {
return false;
}
//类型转换
PriorityQueueNode node = (PriorityQueueNode) o;
//node.priorityQueueIndex(this)取出node在数组中的下标
return contains(node, node.priorityQueueIndex(this));
}
@Override
public boolean containsTyped(T node) {
//node.priorityQueueIndex(this)取出node在数组中的下标
return contains(node, node.priorityQueueIndex(this));
}
//首先i的范围必须大于等于0 并且不超过size
//其次数组中i位置的元素需要eq传入的node
//二者具备说明队列包含此元素
private boolean contains(PriorityQueueNode node, int i) {
return i >= 0 && i < size && node.equals(queue[i]);
}
//清空队列
@Override
public void clear() {
for (int i = 0; i < size; ++i) {
//依次拿出数组中的元素
T node = queue[i];
if (node != null) {
//把元素内部的index设置为INDEX_NOT_IN_QUEUE
node.priorityQueueIndex(this, INDEX_NOT_IN_QUEUE);
//把数组的引用全部设为null
queue[i] = null;
}
}
//size归零
size = 0;
}
//只把size归零,相当于逻辑删除
//quque的引用还在,并且队列元素的index没有改变
@Override
public void clearIgnoringIndexes() {
size = 0;
}
@Override
public boolean offer(T e) {
//如果当前元素的index不是INDEX_NOT_IN_QUEUE,说明已经加入过队列
if (e.priorityQueueIndex(this) != INDEX_NOT_IN_QUEUE) {
//抛出异常
throw new IllegalArgumentException("e.priorityQueueIndex(): " + e.priorityQueueIndex(this) +
" (expected: " + INDEX_NOT_IN_QUEUE + ") + e: " + e);
}
// Check that the array capacity is enough to hold values by doubling capacity.
if (size >= queue.length) {
//增加容量
queue = Arrays.copyOf(queue, queue.length + ((queue.length < 64) ?
(queue.length + 2) :
//右移一位等于除2
(queue.length >>> 1)));
}
//加入到队列(先赋值后++)
bubbleUp(size++, e);
return true;
}
//获取并移除此队列的头,如果此队列为空,则返回 null。
@Override
public T poll() {
if (size == 0) {
return null;
}
//获取头元素
T result = queue[0];
//头元素的index属性标记为不在队列中
result.priorityQueueIndex(this, INDEX_NOT_IN_QUEUE);
//取出最后一个元素并把size--
T last = queue[--size];
//最后一个元素
queue[size] = null;
if (size != 0) { //如果size不为0,需要移动元素
//把后面的元素插入到合适位置
bubbleDown(0, last);
}
return result;
}
//获取队列头部元素
public T peek() {
return (size == 0) ? null : queue[0];
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object o) {
final T node;
try {
node = (T) o;
} catch (ClassCastException e) {
return false;
}
return removeTyped(node);
}
@Override
public boolean removeTyped(T node) {
int i = node.priorityQueueIndex(this);
if (!contains(node, i)) {
return false;
}
node.priorityQueueIndex(this, INDEX_NOT_IN_QUEUE);
if (--size == 0 || size == i) {
// If there are no node left, or this is the last node in the array just remove and return.
queue[i] = null;
return true;
}
// Move the last element where node currently lives in the array.
T moved = queue[i] = queue[size];
queue[size] = null;
// priorityQueueIndex will be updated below in bubbleUp or bubbleDown
// Make sure the moved node still preserves the min-heap properties.
if (comparator.compare(node, moved) < 0) {
bubbleDown(i, moved);
} else {
bubbleUp(i, moved);
}
return true;
}
@Override
public void priorityChanged(T node) {
int i = node.priorityQueueIndex(this);
if (!contains(node, i)) {
return;
}
// Preserve the min-heap property by comparing the new priority with parents/children in the heap.
if (i == 0) {
bubbleDown(i, node);
} else {
// Get the parent to see if min-heap properties are violated.
int iParent = (i - 1) >>> 1;
T parent = queue[iParent];
if (comparator.compare(node, parent) < 0) {
bubbleUp(i, node);
} else {
bubbleDown(i, node);
}
}
}
@Override
public Object[] toArray() {
return Arrays.copyOf(queue, size);
}
@SuppressWarnings("unchecked")
@Override
public <X> X[] toArray(X[] a) {
if (a.length < size) {
return (X[]) Arrays.copyOf(queue, size, a.getClass());
}
System.arraycopy(queue, 0, a, 0, size);
if (a.length > size) {
a[size] = null;
}
return a;
}
/**
* This iterator does not return elements in any particular order.
*/
@Override
public Iterator<T> iterator() {
return new PriorityQueueIterator();
}
private final class PriorityQueueIterator implements Iterator<T> {
private int index;
@Override
public boolean hasNext() {
return index < size;
}
@Override
public T next() {
if (index >= size) {
throw new NoSuchElementException();
}
return queue[index++];
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove");
}
}
//把元素拿出从后往前移动位置
private void bubbleDown(int k, T node) {
//当前队列queue中的元素总数除2
final int half = size >>> 1;
while (k < half) {
// Compare node to the children of index k.
int iChild = (k << 1) + 1;
T child = queue[iChild];
// Make sure we get the smallest child to compare against.
int rightChild = iChild + 1;
if (rightChild < size && comparator.compare(child, queue[rightChild]) > 0) {
child = queue[iChild = rightChild];
}
// If the bubbleDown node is less than or equal to the smallest child then we will preserve the min-heap
// property by inserting the bubbleDown node here.
if (comparator.compare(node, child) <= 0) {
break;
}
// Bubble the child up.
queue[k] = child;
child.priorityQueueIndex(this, k);
// Move down k down the tree for the next iteration.
k = iChild;
}
// We have found where node should live and still satisfy the min-heap property, so put it in the queue.
queue[k] = node;
node.priorityQueueIndex(this, k);
}
//将元素加入到队列合适位置, k为queue的最后一个元素位置+1,也就是可以存储的位置
private void bubbleUp(int k, T node) {
while (k > 0) {
//(k - 1) 正好是目前queue中已经存在的元素数量
//(k - 1) >>>1 相当于除2 二分法
int iParent = (k - 1) >>> 1;
T parent = queue[iParent];
// If the bubbleUp node is less than the parent, then we have found a spot to insert and still maintain
// min-heap properties.
//如果node的延期时间大于parent,则结束循环
if (comparator.compare(node, parent) >= 0) {
break;
}
// Bubble the parent down.
//否则把parent往后挪,放入k位置
queue[k] = parent;
//更新parent在数组中的索引
parent.priorityQueueIndex(this, k);
//把key重新赋值继续二分
k = iParent;
}
queue[k] = node;
node.priorityQueueIndex(this, k);
}
}
测试用例
package com.ht.web.google;
import java.util.Comparator;
import io.grpc.netty.shaded.io.netty.util.internal.DefaultPriorityQueue;
import io.grpc.netty.shaded.io.netty.util.internal.PriorityQueueNode;
public class Rsa {
//UnpooledHeapByteBuf
public static void main(String[] args) throws Exception {
DefaultPriorityQueue queue = new DefaultPriorityQueue<>(new Comparator<MyNode>() {
@Override
public int compare(MyNode o1, MyNode o2) {
return o1.order.compareTo(o2.order);
}
}, 11);
MyNode n1 = new MyNode(1);
MyNode n20 = new MyNode(20);
MyNode n30 = new MyNode(30);
MyNode n40 = new MyNode(40);
MyNode n35 = new MyNode(35);
MyNode n19 = new MyNode(19);
MyNode n18 = new MyNode(18);
MyNode n22 = new MyNode(22);
MyNode n88 = new MyNode(88);
MyNode n90 = new MyNode(90);
MyNode n33 = new MyNode(33);
MyNode n32 = new MyNode(32);
queue.add(n1);
queue.add(n20);
queue.add(n30);
queue.add(n40);
queue.add(n35);
queue.add(n19);
queue.add(n18);
queue.add(n22);
queue.add(n88);
queue.add(n90);
queue.add(n33);
queue.add(n32);
PriorityQueueNode n = null;
while(( n = queue.poll()) != null) {
System.out.println(n);
}
}
public static class MyNode implements PriorityQueueNode {
public MyNode(Integer order) {
super();
this.order = order;
}
public Integer order = 0;
private int index = PriorityQueueNode.INDEX_NOT_IN_QUEUE;
@Override
public int priorityQueueIndex(DefaultPriorityQueue<?> arg0) {
return index;
}
@Override
public void priorityQueueIndex(DefaultPriorityQueue<?> arg0, int arg1) {
this.index = arg1;
}
@Override
public String toString() {
return "order=" + order;
}
}
}
order=1
order=18
order=19
order=20
order=22
order=30
order=32
order=33
order=35
order=40
order=88
order=90