PriorityQueue源码阅读
最小堆:优先级权重越小 离顶点越近
案例
实现一个top max n
publish static int[] topN(int[] nums, int l){
int[] result = new int[l];
Comparator c = new Comparator(){
public int comparable(int a, int b){
return a - b > 0;
}
};
PriorityQueue pq = new PriorityQueue(l, c);
for(int n = 0; n < nums.length; n++){
pq.add(nums[i]);
}
for(int n = 0; n < l; n++){
result[n] = pq.peek();//拿出堆顶元素
}
return result;
}
public void main(String[] args){
int[] nums = {10,5,69,2,14,55,63}; }
问题
添加时向上调整:元素最开始插入的时候是从队尾进入的,所以一直向上比较大小
移除时向下调整:删除时最开始是先将队尾置空,将队尾元素覆盖目标删除位置,然后向下和左右孩子比较
todo
以集合/队列等方式初始化:调整树结构时从队尾开始向下调整
属性及构造器
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {
//表现为一个平衡二叉树:queue[n]为queue[2*n+1]和queue[2*(n+1)]的父节点
transient Object[] queue;
private int size = 0;
//比较器:根据比较器排列元素在队列中的顺序
private final Comparator<? super E> comparator;
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;
}
}
内部类Itr:迭代器
private final class Itr implements Iterator<E> {
private int cursor = 0;
//没被访问过的元素 迭代过程中被落下的元素
private ArrayDeque<E> forgetMeNot = null;
//最近被访问后的元素索引
private int lastRet = -1;
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 {
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;
}
}
扩容
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// 如果原尺寸小于64 则双倍扩容 反之扩容50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) :
(oldCapacity >> 1));
// 保证新尺寸小于Integer.MAX_VALUE 不然内存溢出
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
基本操作
//取堆顶元素
public E peek() {
return (size == 0) ? null : (E) queue[0];
}
添加元素
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;
}
//调整插入 区分是否有自定义的比较器 没有则用对象默认实现的Comparable
//k 默认插入位置 x 插入元素
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
private void siftUpComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;//(k-1)/2
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) {
//找到k位置所在的父节点
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;
}
移除特定元素:如果有多个相等的 只删除第一个
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;
//将队尾元素先覆盖位置i 然后向下做调整
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; // 假设左孩子比右孩子更小
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) {
//得到位置k的左孩子
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];
//如果左/右孩子大于等于目标元素x 跳出循环
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
//将x放入 k是叶子节点
queue[k] = x;
}
PriorityQueue源码阅读的更多相关文章
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】FMDB源码阅读(二)
[原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...
- 【原】FMDB源码阅读(一)
[原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...
- 【原】AFNetworking源码阅读(六)
[原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...
- 【原】AFNetworking源码阅读(五)
[原]AFNetworking源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中提及到了Multipart Request的构建方法- [AFHTTP ...
- 【原】AFNetworking源码阅读(四)
[原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...
- 【原】AFNetworking源码阅读(三)
[原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...
- 【原】AFNetworking源码阅读(二)
[原]AFNetworking源码阅读(二) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中我们在iOS Example代码中提到了AFHTTPSessionMa ...
- 【原】AFNetworking源码阅读(一)
[原]AFNetworking源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 AFNetworking版本:3.0.4 由于我平常并没有经常使用AFNetw ...
随机推荐
- POJ题解Sorting It All Out-传递丢包+倍增
题目链接: http://poj.org/problem?id=1094 题目大意(直接从谷歌翻译上复制下来的): 描述 不同值的递增排序顺序是其中使用某种形式的小于运算符来将元素从最小到最大排序的顺 ...
- 多列表zip合并的csv持久化储存
有时xpath爬取数据之后会返回多个列表,这些列表的长度一样,这时候可以用zip()合并,然后返回一个zip对象,直接传入储存函数,进行持久化储存 例如: name=['张三','李四','王五'] ...
- java 矩阵的运算
首先需要引入包Jama-1.0.2.jar 这个包下封装的对矩阵运算的方法,包括矩阵的加减乘除逆运算等 包下载地址:https://math.nist.gov/javanumerics/jama/ ...
- mysql设计与优化以及数据库表设计与表开发规范
一.设计问题? 1.主键是用自增还是UUID ? Innodb 中的主键是聚簇索引. 如果主键是自增的,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的 ...
- 02 Redis防止入侵
在使用云服务器时,安装的redis3.0+版本都关闭了protected-mode,因而都遭遇了挖矿病毒的攻击,使得服务器99%的占用率!! 因此我们在使用redis时候,最好更改默认端口,并且使用r ...
- css设置全屏背景图,background-size 属性
在写主题样式的时候经常会碰到用背景图铺满整个背景的需求,这里分享下使用方法 需要的效果 图片以背景的形式铺满整个屏幕,不留空白区域 保持图像的纵横比(图片不变形) 图片居中 不出现滚动条 多浏览器支持 ...
- openlayers之点,线,面(以城市,河流,省份为例,分别对应点线面)
kpst._this这里指向初始化的map // 设置标注样式函数 function createStyle(name) { // 河流style var riverStyle = new Style ...
- Swift(二)基础部分
数据类型 Swift 包含了 C 和 Objective-C 上所有基础数据类型.它还增加了 Objective-C 中没有的高阶数据类型比如元组(Tuple) 1.基础类型 Int整形和UInt无符 ...
- 64位Win7安装Oracle12C临时位置权限错误解决方案
今天装备安装Oracle12C体验一下,结果遇到问题:请确保当前用户具有访问临时位置所需的权限,无法继续安装,上网查了一下,解决方案如下: 第一步: 控制面板>所有控制面板项>管理工具 ...
- Linux编译阻塞型驱动遇到'TASK_NORMAL' undeclared (first use in this function)问题解决办法
http://blog.csdn.net/qq_16405157/article/details/49281793