java源码-PriorityQueue
开篇
PriorityQueue是具备了小根堆性质的数据结构也就是优先队列PriorityQueue,内部实现是一个堆排序的数据结构。
PriorityQueue的逻辑结构是一棵完全二叉树,存储结构其实是一个数组。逻辑结构层次遍历的结果刚好是一个数组,如下图。
PriorityQueue类图
PriorityQueue类变量和构造函数
PriorityQueue的类变量当中包含存储元素的数组queue和用于排序的比较器comparator。
PriorityQueue的构造函数参数中包含存储数组的大小initialCapacity和比较器comparator。
PriorityQueue的构造函数针对传入为Collection的对象的时候会依据是否已经排好序进行初始化,针对无序的集合通过heapify进行堆序的构建。
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable { private static final long serialVersionUID = -7720805057305804111L; // 初始化容量大小 private static final int DEFAULT_INITIAL_CAPACITY = 11; // 数据存储数组 transient Object[] queue; // non-private to simplify nested class access private int size = 0; // 容器比较器 private final Comparator<? super E> comparator; transient int modCount = 0; // non-private to simplify nested class access 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) { // Note: This restriction of at least one is not actually needed, // but continues for 1.5 compatibility 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); } } @SuppressWarnings("unchecked") public PriorityQueue(PriorityQueue<? extends E> c) { this.comparator = (Comparator<? super E>) c.comparator(); initFromPriorityQueue(c); } @SuppressWarnings("unchecked") public PriorityQueue(SortedSet<? extends E> c) { this.comparator = (Comparator<? super E>) c.comparator(); initElementsFromCollection(c); } private void initFromPriorityQueue(PriorityQueue<? extends E> c) { if (c.getClass() == PriorityQueue.class) { this.queue = c.toArray(); this.size = c.size(); } else { initFromCollection(c); } } private void initElementsFromCollection(Collection<? extends E> c) { Object[] a = c.toArray(); // If c.toArray incorrectly doesn't return Object[], copy it. if (a.getClass() != Object[].class) a = Arrays.copyOf(a, a.length, Object[].class); int len = a.length; if (len == 1 || this.comparator != null) for (int i = 0; i < len; i++) if (a[i] == null) throw new NullPointerException(); this.queue = a; this.size = a.length; } private void initFromCollection(Collection<? extends E> c) { initElementsFromCollection(c); heapify(); } }
PriorityQueue的add操作
PriorityQueue的add操作主要是在offer()函数当中,整体执行逻辑如下:
判断数组大小并通过grow进行扩容:
- 如果数组为为空则第一个加入元素就直接添加。
- 如果数组不为空则添加元素到末尾并通过siftUp上浮元素到合适的位置。
- 上浮的过程就是堆排序的过程的,通过和父节点进行比较继而上浮。
public boolean add(E e) { return offer(e); } public boolean offer(E e) { if (e == null) throw new NullPointerException(); modCount++; //这里原来size大小就是新增元素后的最后一个元素下标 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; } private void grow(int minCapacity) { int oldCapacity = queue.length; // Double size if small; else grow by 50% int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1)); // overflow-conscious code if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); queue = Arrays.copyOf(queue, newCapacity); } private void siftUp(int k, E x) { if (comparator != null) siftUpUsingComparator(k, x); else siftUpComparable(k, x); } @SuppressWarnings("unchecked") private void siftUpComparable(int k, E x) { Comparable<? super E> key = (Comparable<? super E>) x; while (k > 0) { int parent = (k - 1) >>> 1; Object e = queue[parent]; if (key.compareTo((E) e) >= 0) break; queue[k] = e; k = parent; } queue[k] = key; } @SuppressWarnings("unchecked") 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; } private void siftDown(int k, E x) { if (comparator != null) siftDownUsingComparator(k, x); else siftDownComparable(k, x); }
PriorityQueue的remove操作
PriorityQueue的remove操作主要过程有两个过程:
- 通过遍历数组找到对应的下标index。
- 将最后一个元素和index节点的左右子节点进行比较然后下沉到合适的位置。
- 最后一个元素设置为null即可。
private int indexOf(Object o) { if (o != null) { for (int i = 0; i < size; i++) if (o.equals(queue[i])) return i; } return -1; } public boolean remove(Object o) { int i = indexOf(o); if (i == -1) return false; else { removeAt(i); return true; } } private E removeAt(int i) { // assert i >= 0 && i < size; modCount++; int s = --size; if (s == i) // removed last element 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; } private void siftDown(int k, E x) { if (comparator != null) siftDownUsingComparator(k, x); else siftDownComparable(k, x); } @SuppressWarnings("unchecked") private void siftDownComparable(int k, E x) { Comparable<? super E> key = (Comparable<? super E>)x; int half = size >>> 1; // loop while a non-leaf while (k < half) { int child = (k << 1) + 1; // assume left child is least Object c = queue[child]; int right = child + 1; if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0) c = queue[child = right]; if (key.compareTo((E) c) <= 0) break; queue[k] = c; k = child; } queue[k] = key; } @SuppressWarnings("unchecked") 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; }
PriorityQueue的heapify操作
PriorityQueue的堆构造过程递归的执行从(n/2-1)至0递归进行构建,这个过程可以参考java源码-PriorityBlockingQueue的构建过程。
。
private void heapify() { for (int i = (size >>> 1) - 1; i >= 0; i--) siftDown(i, (E) queue[i]); } private void siftDown(int k, E x) { if (comparator != null) siftDownUsingComparator(k, x); else siftDownComparable(k, x); } @SuppressWarnings("unchecked") private void siftDownComparable(int k, E x) { Comparable<? super E> key = (Comparable<? super E>)x; int half = size >>> 1; // loop while a non-leaf while (k < half) { int child = (k << 1) + 1; // assume left child is least Object c = queue[child]; int right = child + 1; if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0) c = queue[child = right]; if (key.compareTo((E) c) <= 0) break; queue[k] = c; k = child; } queue[k] = key; } @SuppressWarnings("unchecked") 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; }
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
conda的安装和VSCode下的配置方法
conda的安装和配置方法 安装miniconda 1.1 说明 conda是一个开源的软件包管理工具和环境管理系统,可以轻松创建多个软件环境,并在多个环境之间轻松切换。例如,我们可以分别创建python3和python2的独立软件环境,并在需要该环境时轻松进行切换(根据工作目录)。 conda的配置工具有两个,miniconda(命令行工具,占用空间约400M),anaconda(GUI工具,占用空间约3G)。 想都不用想,肯定是用miniconda啦,毕竟配置的时间非常短,没什么大不了的。 1.2 下载安装包 下载官方miniconda安装包,在下载页面选择对应平台的安装包进行安装。 自带python环境,可以根据自己长期使用的版本进行选择,但是不建议在默认环境下安装软件包。 1.3 安装注意事项 下载好安装包后,安装时可以选择作为用户软件安装(储存到用户文件夹),或者做为系统软件安装(所有用户都可以使用) 到下面这一步时,勾选两个选项,其他按默认 这两个选项分别是,添加miniconda至环境变量PATH,注册miniconda所带的python为默认环境。 如果你的环境里已经有...
- 下一篇
Linux命令之curl
获取http请求头信息,-I 只打印response header, -i 打印response header和body curl -I "http://www.jouypub.com" curl -i "http://www.jouypub.com" 使用代理 curl -x 1.193.162.91:8000 http://www.jouypub.com curl -x 1.193.162.91:8000 --connect-timeout 3 --max-time 10 http://www.jouypub.com 上传文件curl -F "filename=@/home/test/file.tar.gz" http://localhost/action.php -F参数,curl就会以 multipart/form-data 的方式发送POST请求。-F参数以name=value的方式来指定参数内容,如果值是一个文件,则需要以name=@file的方式来指定。 选项 -d 以post方式请求 -H 请求时添加header,冒号前后不能有空格 curl -H "name=abc"...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2整合Redis,开启缓存,提高访问速度
- MySQL8.0.19开启GTID主从同步CentOS8
- Hadoop3单机部署,实现最简伪集群
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16