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
- JDK容器与并发—Queue—PriorityQueue
- JDK容器与并发—Queue
- JDK容器与并发—Queue—Interface
- JDK容器与并发—Queue—ArrayBlockingQueue
- JDK容器与并发—Queue—LinkedBlockingQueue
- JDK容器与并发—Queue—PriorityBlockingQueue
- JDK容器与并发—Queue—DelayQueue
- JDK容器与并发—Queue—ConcurrentLinkedQueue
- JDK容器与并发—Queue—LinkedTransferQueue
- JDK容器与并发—Queue—SynchronousQueue
- JDK容器与并发—并发
- JDK容器与并发—JDK容器框架
- JDK容器与并发—数据结构
- JDK容器与并发—List
- JDK容器与并发—Map
- JDK容器与并发—List—ArrayList
- JDK容器与并发—List—LinkedList
- JDK容器与并发—List—CopyOnWriteArrayList
- 1.Http的Post与Get区别与联系,实践中如何选择它们?
- LightOj 1341
- PHP 文件打开/读取/读取
- 玩得开心
- window10使用命令ssh工具生成github开源中国需要的ssh密钥以及转换为ppk让tortriseGit工具支持它
- JDK容器与并发—Queue—PriorityQueue
- LeetCode *** 90. Subsets II
- Unity3D-深入剖析NGUI的游戏UI架构
- git 远程仓库回滚
- PHP中读写文件实现代码
- C#—密度较量拓展
- 推理逻辑算法--------------问题抽象与数学建模
- 排序算法之二:冒泡、插入、希尔、快排、归并
- Opengl备忘--创建一个简单GLFW窗口