Java源码阅读PriorityQueue
1类签名与简介
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable
PriorityQueue是一个基于优先级堆的无限队列,无限的意思是说队列的容量可以自动扩容,最大容量为整形最大值。扩容规定如下当容量小于64时扩大为原来的2倍,否则扩大为原来的1.5倍(也就是容量增大50%)。
优先级队列不允许null元素,也不允许插入不可比较的对象。不可比较是指待插入对象的类没有实现Comparable接口,或者构造PriorityQueue对象是没有提供一个待插入对象的comparator比较器。强行插入不可比较对象会报ClassCastException异常。举个例子,现有一个Student类,只有以下两种情况才能将Student的对象放入PriorityQueue中:
(1)Student实现Comparable接口
(2)new PriorityQueue时提供一个Student的比较器:Queue<Student> students = new PriorityQueue<>(new MyComparator())
该队列的头部是相对于指定顺序的最小元素。 如果多个元素被绑定到最小值,那么头就是这些元素之一。
优先级堆(小顶堆)是用数组实现的,对于小顶堆的性质请执行查阅相关数据结构。入队出队的方法时间复杂度都是O(logn)。
请注意,此实现不同步。若想要在多线程并发,请使用线程安全的PriorityBlockingQueue类。
2 入队
public 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;
else
siftUp(i, e);
return true;
}
add和offer都是入队实现,add其实就是调用offer方法实现的,所以两者本质上没有区别。
offer首先会判断插入元素是否为null,优先队列不允许插入null的元素。接下来判断队列是否满了,满了就扩容。如果插入的是队列第一个元素就直接放在数组0号位。否则就进行上移调整siftUp。上移调整是从堆的最后一个节点(也就是队尾)开始不断通过比较parent节点找到插入的位置。
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
//实现Comparable接口的情况
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;
}
//提供比较器Comparator的情况
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;
}
每次插入都进行siftUp保证了始终是一个小顶堆,不会因为新的节点破坏堆的结构。
siftUpComparable和siftUpUsingComparator过程是一样的,唯一不同的是不同的接口调用的不同比较方法。
3出队
出队是移除队列队头的元素,即数组的0号位存储的元素,也是堆结构的堆顶。
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;
}
poll原理如下,把最后一个元素放到堆顶(数组0号位),然后从堆顶开始往下调整siftDown,直到满足最小堆为止。siftDown实现过程如下
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
//内部排序接口调用siftDownComparable
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;
}
//有外部比较器调用siftDownUsingComparator
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;
}
4总结
关于本篇文章,个人感觉描述的不是很清楚。
因为觉得不适合花费其他篇幅去详细介绍“Comparator与Comparable”以及堆排序等相关知识。如果觉得有问题的话建议先了解一下这些相关的基础知识。
Java源码阅读PriorityQueue的更多相关文章
- Java源码阅读的真实体会(一种学习思路)
Java源码阅读的真实体会(一种学习思路) 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈 ...
- Java源码阅读的真实体会(一种学习思路)【转】
Java源码阅读的真实体会(一种学习思路) 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+ ...
- 如何阅读Java源码 阅读java的真实体会
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比 ...
- [收藏] Java源码阅读的真实体会
收藏自http://www.iteye.com/topic/1113732 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我 ...
- java源码阅读Hashtable
1类签名与注释 public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, C ...
- Java源码阅读Stack
Stack(栈)实现了一个后进先出(LIFO)的数据结构.该类继承了Vector类,是通过调用父类Vector的方法实现基本操作的. Stack共有以下五个操作: put:将元素压入栈顶. pop:弹 ...
- Java源码阅读顺序
阅读顺序参考链接:https://blog.csdn.net/qq_21033663/article/details/79571506 阅读源码:JDK 8 计划阅读的package: 1.java. ...
- java源码阅读LinkedBlockingQueue
1类签名与简介 public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements Blocking ...
- java源码阅读ArrayBlockingQueue
1类签名与简介 public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQ ...
随机推荐
- Codeforces 270E Flawed Flow 网络流问题
题意:给出一些边,给出边的容量.让你为所有边确定一个方向使得流量最大. 题目不用求最大流, 而是求每条边的流向,这题是考察网络流的基本规律. 若某图有最大,则有与源点相连的边必然都是流出的,与汇点相连 ...
- CSS边框属性
边框 圆角 border-radius border-top-left-radius border-top-right-radius border-bottom-left-radlius border ...
- SSH的简单入门体验(Struts2.1+Spring3.1+Hibernate4.1)- 查询系统(下)
我们继续吧,SSH最大的优点就是实现的系统的松耦合,能够将后台和前台有机的分离开来. 一.目录结构 一个好的程序要有一个好的开始.我们先来看看整个目录结构吧 主要的是三层架构概念,或者说是mvc的概念 ...
- django一对多、多对多模型、自关联的建立
# 原创,转载请留言联系 一对多模型 一对多的关系,例如员工跟部门.一个部门有多个员工.那么在django怎么建立这种表关系呢? 其实就是利用外键,在多的一方,字段指定外键即可.例如员工和部门,员工是 ...
- centos内核参数调优
[net] ######################## cat /proc/sys/net/ipv4/tcp_syncookies # 默认值: # 作用:是否打开SYN Cookie功能,该功 ...
- Photoshop CC 2015
1.Ctrl 加 + -号实现放大缩小2.Ctrl+T 自由变换3.Ctrl+D 取消选区,再选择处理完后想要选中别的区域的话要取消之前选中的区域,要不然之前的区域一直都是选中状态4.F12 将文件恢 ...
- Linux命令之vi/vim(一)
vi仅仅是一个文本编辑器,可以给字符着色,可以自动补全,但不具备windows下word的排版功能.Vim是Vi improved的缩写,是vi的改进版. vi和vim的区别: 多级撤销.在vi中按u ...
- Python __call__内置函数的作用和用法
开学了进入了实验室,需要协助大师兄做事,主要是OpenStack中的代码解析,但是涉及很多python高级用法,一时间有点麻烦,在做项目的同时慢慢更新博客.这次先写一下__call__的用法,因为经常 ...
- 通用数据库管理工具DBeaver
通用数据库管理工具DBeaver 在渗透测试中,用户往往需要管理很多数据库.这些数据库可能是渗透软件使用的(如Metasploit使用的Postgresql),也有目标主机的数据库(如网站的数据库 ...
- Mysql数据库的安装及配置
本文转载自http://www.cnblogs.com/xiaoluo501395377/archive/2013/04/07/3003278.html 如果要在Linux上做j2ee开发,首先得搭建 ...