7赞
661
当前位置:  开发笔记 > 编程语言 > 正文

【Java】PriorityQueue的实现原理

一、PriorityQueue介绍PriorityQueue是基于优先级堆的无限优先级queue 。 优先级队列的元素根据它们的有序naturalordering ,或由一个Com

一、PriorityQueue介绍

  PriorityQueue 是基于优先级堆的无限优先级queue 。 优先级队列的元素根据它们的有序natural ordering ,或由一个Comparator在队列构造的时候提供,这取决于所使用的构造方法。 优先队列不允许null元素。 依靠自然排序的优先级队列也不允许插入不可比较的对象(这样做可能导致ClassCastException )。

  该队列的头部是相对于指定顺序的最小元素(即最小堆数据结构)。 如果多个元素被绑定到最小值,那么头就是这些元素之一 - 关系被任意破坏。 队列检索操作poll , remove , peekelement访问在队列的头部的元件。

  优先级队列是无限制的,但是具有管理用于在队列上存储元素的数组的大小的内部容量 。 它始终至少与队列大小一样大。 当元素被添加到优先级队列中时,其容量会自动增长。 没有规定增长政策的细节。


二、属性


1 // 默认队列容量
2 private static final int DEFAULT_INITIAL_CAPACITY = 11;
3
4 // 数据数组
5 transient Object[] queue;
6
7 // 队列大小
8 private int size = 0;
9
10 // 比较器
11 private final Comparatorsuper E> comparator;
12
13 // 修改次数
14 transient int modCount = 0;


三、方法


1、构造方法


1 // 创建默认优先级队列,队列默认容量为11,其中数据数组未创建
2 public PriorityQueue() {
3 this(DEFAULT_INITIAL_CAPACITY, null);
4 }
5
6 // 根据初始值容量创建优先级队列
7 public PriorityQueue(int initialCapacity) {
8 this(initialCapacity, null);
9 }
10
11 // 根据创建比较器,默认容量为11优先级队列
12 public PriorityQueue(Comparatorsuper E> comparator) {
13 this(DEFAULT_INITIAL_CAPACITY, comparator);
14 }
15
16 // 根据初始值容量,比较器,创建队列
17 public PriorityQueue(int initialCapacity,
18 Comparatorsuper E> comparator) {
19 // Note: This restriction of at least one is not actually needed,
20 // but continues for 1.5 compatibility
21 if (initialCapacity <1)
22 throw new IllegalArgumentException();
23 this.queue = new Object[initialCapacity];
24 this.comparator = comparator;
25 }
26
27 // 根据集合创建优先级队列
28 @SuppressWarnings("unchecked")
29 public PriorityQueue(Collectionextends E> c) {
30 if (c instanceof SortedSet) {
31 SortedSetextends E> ss = (SortedSetextends E>) c;
32 this.comparator = (Comparatorsuper E>) ss.comparator();
33 initElementsFromCollection(ss);
34 }
35 else if (c instanceof PriorityQueue) {
36 PriorityQueueextends E> pq = (PriorityQueueextends E>) c;
37 this.comparator = (Comparatorsuper E>) pq.comparator();
38 initFromPriorityQueue(pq);
39 }
40 else {
41 this.comparator = null;
42 initFromCollection(c);
43 }
44 }
45
46 // 根据原优先级队列创建队列
47 @SuppressWarnings("unchecked")
48 public PriorityQueue(PriorityQueueextends E> c) {
49 this.comparator = (Comparatorsuper E>) c.comparator();
50 initFromPriorityQueue(c);
51 }
52
53 // 根据SortSet集合创建优先级队列
54 @SuppressWarnings("unchecked")
55 public PriorityQueue(SortedSetextends E> c) {
56 this.comparator = (Comparatorsuper E>) c.comparator();
57 initElementsFromCollection(c);
58 }


2、add() 和 offer() 方法


1 // 添加元素到队列中
2 public boolean add(E e) {
3 return offer(e);
4 }
5
6 // 放入元素到队列中
7 public boolean offer(E e) {
8 if (e == null)
9 throw new NullPointerException();
10 modCount++;
11 int i = size;
12 // 队列大小 大于等于 队列容量时
13 if (i >= queue.length)
14 // 对队列进行扩容
15 grow(i + 1);
16 size = i + 1;
17 if (i == 0)
18 // 队列中没有元素
19 queue[0] = e;
20 else
21 // 使用的数组形式存储的“二叉堆”数据,上浮
22 // 二叉堆可自己百度
23 // 保持数据并上浮
24 siftUp(i, e);
25 return true;
26 }

  注:不明白二叉堆-最小堆的可百度,即可理解原理


3、grow() 方法


1 // 扩容
2 private void grow(int minCapacity) {
3 int oldCapacity = queue.length;
4 // Double size if small; else grow by 50%
5 // 1、原容量小于 64,新容量为原容量的2倍+2
6 // 2、原容量不小于 64,新容量为原容量的1.5倍
7 int newCapacity = oldCapacity + ((oldCapacity <64) ?
8 (oldCapacity + 2) :
9 (oldCapacity >> 1));
10 // overflow-conscious code
11 if (newCapacity - MAX_ARRAY_SIZE > 0)
12 // 新容量大于数组最大长度时,新容量为:Integer.MAX_VALUE,否则为:MAX_ARRAY_SIZE
13 newCapacity = hugeCapacity(minCapacity);
14 // 复制数据到新数组
15 queue = Arrays.copyOf(queue, newCapacity);
16 }


4、siftUp() 方法


1 // 筛选 siftUp
2 private void siftUp(int k, E x) {
3 if (comparator != null)
4 siftUpUsingComparator(k, x);
5 else
6 siftUpComparable(k, x);
7 }
8
9 // 使用选择器上浮
10 @SuppressWarnings("unchecked")
11 private void siftUpComparable(int k, E x) {
12 Comparablesuper E> key = (Comparablesuper E>) x;
13 while (k > 0) {
14 int parent = (k - 1) >>> 1;
15 Object e = queue[parent];
16 if (key.compareTo((E) e) >= 0)
17 break;
18 queue[k] = e;
19 k = parent;
20 }
21 queue[k] = key;
22 }
23
24 // 使用选择器上浮
25 @SuppressWarnings("unchecked")
26 private void siftUpUsingComparator(int k, E x) {
27 while (k > 0) {
28 // 使用的
29 int parent = (k - 1) >>> 1;
30 Object e = queue[parent];
31 if (comparator.compare(x, (E) e) >= 0)
32 break;
33 queue[k] = e;
34 k = parent;
35 }
36 queue[k] = x;
37 }


5、poll() 方法


1 public E poll() {
2 if (size == 0)
3 return null;
4 int s = --size;
5 modCount++;
6 // 因为数据时最小堆,所以queue[0]最小
7 E result = (E) queue[0];
8 E x = (E) queue[s];
9 queue[s] = null;
10 if (s != 0)
11 // 二叉堆存储
12 // 下浮
13 siftDown(0, x);
14 return result;
15 }


6、siftDown() 方法


1 private void siftDown(int k, E x) {
2 if (comparator != null)
3 siftDownUsingComparator(k, x);
4 else
5 siftDownComparable(k, x);
6 }
7
8 @SuppressWarnings("unchecked")
9 private void siftDownComparable(int k, E x) {
10 Comparablesuper E> key = (Comparablesuper E>)x;
11 int half = size >>> 1; // loop while a non-leaf
12 while (k < half) {
13 int child = (k <<1) + 1; // assume left child is least
14 Object c = queue[child];
15 int right = child + 1;
16 if (right 17 ((Comparablesuper E>) c).compareTo((E) queue[right]) > 0)
18 c = queue[child = right];
19 if (key.compareTo((E) c) <= 0)
20 break;
21 queue[k] = c;
22 k = child;
23 }
24 queue[k] = key;
25 }
26
27 @SuppressWarnings("unchecked")
28 private void siftDownUsingComparator(int k, E x) {
29 int half = size >>> 1;
30 while (k < half) {
31 int child = (k <<1) + 1;
32 Object c = queue[child];
33 int right = child + 1;
34 if (right 35 comparator.compare((E) c, (E) queue[right]) > 0)
36 c = queue[child = right];
37 if (comparator.compare(x, (E) c) <= 0)
38 break;
39 queue[k] = c;
40 k = child;
41 }
42 queue[k] = x;
43 }


四、总结

  1、PriorityQueue 采用数组来存储数据的,数据结构是最小堆

  2、PriorityQueue 扩容时

    - 原容量小于 64,新容量为原容量的2倍+2

    - 原容量不小于 64,新容量为原容量的1.5倍

  3、放入元素,需要使用siftUp() 上浮方法,保证最小堆结构

  4、取出元素,需要使用downtUp() 下浮方法,保证最小堆结构

  5、PriorityQueue 非线程安全的,线程安全可以使用 PriorityBlockingQueue

【Java】PriorityQueue 的实现原理



推荐阅读
author-avatar
葉の鋼琴曲
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有