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 ...
随机推荐
- JVM - Java虚拟机规范官方文档
Java虚拟机规范官方文档
- N4语法
第一期 授受关系 这里讲的授受关系是指“物的收受”也就是前后两个主体之前的“物的收受”. 请看以下三个基本句型:(从接收者B来分析) 1. AはBに-を あげる(平辈.晚辈) (A给 ...
- MySQL 下载与安装
从MySQL官网下载安装文件,我的电脑是window10 64位的,下载社区版本,选择mysql community server,再下载64位的. 官网链接:https://www.mysql.co ...
- ubuntu - 如何以root身份使用图形界面管理文件?
nautilus 是gnome的文件管理器,但是如果不是root账号下,权限受限,我们可以通过以下方式以root权限使用! 一,快捷键“ctrl+alt+t”,调出shell. 二,在shell中输入 ...
- win7-32位安装mysql-5.7.27
下载 https://dev.mysql.com/downloads/mysql/5.7.html#downloads 参考链接 https://blog.csdn.net/qq_41307443/a ...
- deep_learning_LSTM长短期记忆神经网络处理Mnist数据集
1.RNN(Recurrent Neural Network)循环神经网络模型 详见RNN循环神经网络:https://www.cnblogs.com/pinard/p/6509630.html 2. ...
- sed命令替换文件内容
reference: https://www.cnblogs.com/starof/p/4181985.html 抓取目录名并修改 ls | grep "XXX" > 1.t ...
- 批量处理window下^M符号
#!/bin/ksh #set -x # #去掉文件中的^M 符号 # usage() { echo "Usage : sh ToAscll.sh [Option] [value]" ...
- zencart批量设置热卖商品 best seller、点击最高最受欢迎产品 most popular
zencart批量设置某分类下热卖商品数 best seller ; ,,,,,); zencart批量设置某产品点击最高最受欢迎产品 most popular ; ,,,,,);
- GlusterFS 分布式文件系统
简介 官方文档:https://docs.gluster.org/en/latest/Quick-Start-Guide/Architecture/ Glusterfs是一个开源的分布式文件系统,是S ...