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