JDK容器与并发—Queue—PriorityQueue

来源:互联网 发布:聊天室程序源码java 编辑:程序博客网 时间:2024/05/21 22:40

概述

      基于优先堆的无界优先队列,非线程安全。

1)add、offer、remove、poll的时间复杂度为O(log(n));remove(Object)、contains(Object)为线性时间;peek、element、size为固定时间;

2)迭代器fail-fast。

数据结构

      基于数组的平衡二叉堆:

// queue[n]元素的两个children为queue[2*n+1]、queue[2*(n+1)]// queue[n]<=queue[2*n+1]且queue[n]<=queue[2*(n+1)]// queue[0]为最小值private transient Object[] queue;

构造器

// 无参构造,初始容量为DEFAULT_INITIAL_CAPACITY=11,采用元素自然排序public PriorityQueue() {this(DEFAULT_INITIAL_CAPACITY, null);}// 带初始容量参数构造public PriorityQueue(int initialCapacity) {this(initialCapacity, null);}// 带初始容量、comparator参数构造public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {// Note: This restriction of at least one is not actually needed,// but continues for 1.5 compatibilityif (initialCapacity < 1)throw new IllegalArgumentException();this.queue = new Object[initialCapacity];this.comparator = comparator;}// 带Collection参数构造public PriorityQueue(Collection<? extends E> c) {if (c instanceof SortedSet<?>) { // SortedSets是特殊的平衡二叉堆,但需要稍调整,转化为Object[],元素不能为nullSortedSet<? extends E> ss = (SortedSet<? extends E>) c;this.comparator = (Comparator<? super E>) ss.comparator();initElementsFromCollection(ss);}else if (c instanceof PriorityQueue<?>) { // PriorityQueue参数,直接拿来用PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;this.comparator = (Comparator<? super E>) pq.comparator();initFromPriorityQueue(pq);}else {  // 对普通的Collection,转化为Object[],元素不能为null,还要对其heapifythis.comparator = null;initFromCollection(c);}}// 带PriorityQueue参数构造public PriorityQueue(PriorityQueue<? extends E> c) {this.comparator = (Comparator<? super E>) c.comparator();initFromPriorityQueue(c);}// 带SortedSet参数构造public PriorityQueue(SortedSet<? extends E> c) {this.comparator = (Comparator<? super E>) c.comparator();initElementsFromCollection(c);}

增删查

容器调整策略(避免无限制扩展)

      步骤:
1)当queue已满,若有元素入队请求,则进行容量扩展;
2)oldCapacity小于64则容量翻倍;否则增长50%;
3)检查newCapacity是否在MAX_ARRAY_SIZE范围内,若minCapacity有overflow,抛出OutOfMemoryError异常;否则容量最大不超过Integer.MAX_VALUE;
4)创建新容量的Object[],将旧的queue元素复制过来。

// 当queue已满时,则进行容量扩展if (i >= queue.length)grow(i + 1);private void grow(int minCapacity) {int oldCapacity = queue.length;// oldCapacity小于64则容量翻倍;否则增长50%int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1));// newCapacity都超过了MAX_ARRAY_SIZE,检查minCapacity是否有溢出if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);queue = Arrays.copyOf(queue, newCapacity);} private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflow,抛出OutOfMemoryError异常throw new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ? // 最大不能超过Integer.MAX_VALUEInteger.MAX_VALUE :MAX_ARRAY_SIZE;}

基础方法

// 对元素x,从k往前移,保持二叉堆的平衡性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;}// 对元素x,从k往后移,保持二叉堆的平衡性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;}

      步骤:
1)检查队列是否已满,若满则进行容量扩展;
2)从队尾,对元素进行siftUp,保持二叉堆的平衡性;
3)返回true

// 因无容量限制,add委托给offerpublic 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;elsesiftUp(i, e);   // 从对尾,对元素进行siftUpreturn true;}

步骤:
1)检查队列是否为空,为空则返回null;
2)取出队列最后一个元素,从索引0开始,对其进行siftDown,保持二叉堆的平衡性;
3)返回队首元素值。

// 将队首元素出队public E poll() {if (size == 0)// 队列为空,返回nullreturn null;int s = --size;modCount++;E result = (E) queue[0];E x = (E) queue[s];    // 取出队列最后一个元素queue[s] = null;if (s != 0)siftDown(0, x);   // 从0开始,对最后一个元素进行siftDownreturn result;}// Collection方法,删除内部元素public boolean remove(Object o) {int i = indexOf(o);// 确定索引位置if (i == -1)return false;else {removeAt(i);   // 删除该元素return true;}}// 删除索引i的元素private E removeAt(int i) {assert i >= 0 && i < size;modCount++;int s = --size;if (s == i)    // 若删除的索引i元素为最后一个元素,直接赋为nullqueue[i] = null;else {E moved = (E) queue[s];   // 取出队列最后一个元素queue[s] = null;siftDown(i, moved);   // 从索引i开始,对最后一个元素进行siftDownif (queue[i] == moved) {   // 若取出的最后一个元素比i+1及其后的元素都小siftUp(i, moved);   // 对取出的最后一个元素,从索引i开始,进行siftUpif (queue[i] != moved)return moved;}}return null;}

步骤:
1)检查队列是否为空,为空则返回null;
2)返回队首元素值。

public E peek() {if (size == 0)return null;return (E) queue[0];}

迭代器

      不保证元素的迭代顺序:

private final class Itr implements Iterator<E> {private int cursor = 0;private int lastRet = -1;// 某些元素因为删除,为了保持二叉堆的平衡性,更换到遍历过的索引位置// 为了确保都遍历到,这里缓存下private ArrayDeque<E> forgetMeNot = null;private E lastRetElt = null;private int expectedModCount = modCount;public boolean hasNext() {return cursor < size ||(forgetMeNot != null && !forgetMeNot.isEmpty());}public E next() {if (expectedModCount != modCount)throw new ConcurrentModificationException();if (cursor < size)return (E) queue[lastRet = cursor++];if (forgetMeNot != null) {lastRet = -1;lastRetElt = forgetMeNot.poll();if (lastRetElt != null)return lastRetElt;}throw new NoSuchElementException();}public void remove() {if (expectedModCount != modCount)throw new ConcurrentModificationException();if (lastRet != -1) {E moved = PriorityQueue.this.removeAt(lastRet);lastRet = -1;if (moved == null)cursor--;else { // moved不为null,说明最后一个元素更换到了遍历前的位置if (forgetMeNot == null)forgetMeNot = new ArrayDeque<>();forgetMeNot.add(moved);}} else if (lastRetElt != null) {PriorityQueue.this.removeEq(lastRetElt);lastRetElt = null;} else {throw new IllegalStateException();}expectedModCount = modCount;}}

特性

      用平衡二叉堆的性质保证优先。

0 0