PriorityQueue简介 PriorityQueue是java.util包下实现Queue接口的非线程安全的优先级队列
也是由数组实现,类似ArrayList通过复制数组达到扩容的操作
其特点是可以按照自定义的元素比较器的规则输出队列元素,默认是按小到大的输出顺序
该队列不允许插入null或不可比较的对象(没有实现Comparable接口的对象)
类定义如下:
1 2 public class PriorityQueue <E> extends AbstractQueue <E> implements java .io.Serializable
属性信息 1 2 3 4 5 6 7 8 9 10 11 12 private static final int DEFAULT_INITIAL_CAPACITY = 11 ;transient Object[] queue;private int size = 0 ;private final Comparator<? super E> comparator;
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public PriorityQueue () { this (DEFAULT_INITIAL_CAPACITY, null ); } public PriorityQueue (int initialCapacity) { this (initialCapacity, null ); } public PriorityQueue (Comparator<? super E> comparator) { this (DEFAULT_INITIAL_CAPACITY, comparator); } public PriorityQueue (int initialCapacity, Comparator<? super E> comparator) { if (initialCapacity < 1 ) throw new IllegalArgumentException (); this .queue = new Object [initialCapacity]; this .comparator = comparator; } 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); } }
核心方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 private void heapify () { for (int i = (size >>> 1 ) - 1 ; i >= 0 ; i--) siftDown(i, (E) queue[i]); } private void grow (int minCapacity) { int oldCapacity = queue.length; int newCapacity = oldCapacity + ((oldCapacity < 64 ) ? (oldCapacity + 2 ) : (oldCapacity >> 1 )); if (newCapacity - MAX_ARRAY_SIZE > 0 ) newCapacity = hugeCapacity(minCapacity); queue = Arrays.copyOf(queue, newCapacity); } private void siftDown (int k, E x) { if (comparator != null ) siftDownUsingComparator(k, x); else siftDownComparable(k, x); } 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; } private void siftUp (int k, E x) { if (comparator != null ) siftUpUsingComparator(k, x); else siftUpComparable(k, x); } 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; }
基本操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 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 ; } 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; } private E removeAt (int i) { modCount++; int s = --size; if (s == i) 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 ; }
通过siftDown()和siftUp()方法可以看出,优先队列是借助数组实现了一个二叉堆。
二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。 二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。 二叉堆一般用数组来表示。如果根节点在数组中下标为0,下标n的元素子节点下标为2n+1和2n+2。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 PriorityQueue<Integer> queue = Queues.newPriorityQueue(); queue.add(5 ); queue.add(3 ); queue.add(10 ); queue.add(6 ); queue.add(2 ); queue.add(2 ); queue.add(1 ); queue.add(6 ); for (Integer i:queue){ System.out.print(i); System.out.print("," ); } System.out.println(); while (queue.size()>0 ){ System.out.print(queue.poll()); System.out.print("," ); }
上述的代码示例可以看到PriorityQueue每次弹出时都会重新整理元素顺序。
小结 优先级队列的结构其实比较简单,是一个用数组实现的二叉堆来保证元素的弹出顺序。