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 ...
随机推荐
- redis 学习(5)-- 列表类型
redis 学习(5)-- 列表类型 列表特点 有序.可以重复.左右两边插入弹出 索引相关知识 索引从左往右,从0开始逐个增大 0 1 2 3 4 5 索引从右往左,从-1开始逐个减小 -6 -5 - ...
- SQL学习(二)之四大查询语句以及标准写法
SQL四大查询语句——增删改查 增-INSERT INSERT INTO 表 (字段列表) VALUES(值列表) INSERT INTO `user_table` (`ID`, `username` ...
- Vue实例:vue2.0+ElementUI框架开发pc项目
开发前准备 vue.js2.0中文,项目所使用的js框架 vue-router,vue.js配套路由 vuex,状态管理 Element,UI框架 1,根据官方指引,构建项目框架 安装vue npm ...
- Django框架——基础之路由系统(urls.py)11111111
1.URL路由系统前言 URL是Web服务的入口,用户通过浏览器发送过来的任何请求,都是发送到一个指定的URL地址,然后被响应. 在Django项目中编写路由,就是向外暴露我们接收哪些URL的请求,除 ...
- css 规范标签
页头:header 登录条:loginBar 标志:logo 侧栏:sideBar 广告:banner 导航:nav 子导航:subNav 菜单:menu 子菜单:subMenu 搜索:search ...
- 升级python导致yum报错的解决方法
把python从2.7升级到3.6后 , 使用yum报错 File ‘’/usr/bin/yum'', line 30 except KeyboardInterrupt, e: ^ 故障原因:yum采 ...
- 你所不知的VIM强大功能
1. 可视化区块(Visual Block) (1)cd ~ 切换到自己的家目录(本范例中为root用户) (2)touch test1 test2 建立两个文件做演示(3)last > tes ...
- jQuery和Prototype的兼容性和冲突的多种解决方法
有两种情况: 1.先加载Prototype,再加载jQuery. 2.先加载jQuery,再加载Prototype. 针对情况1:先加载Prototype,再加载jQuery.方法一:jQuery 库 ...
- Java常用类库——观察者设计模式
观察者设计模式 现在很多的购房者都在关注着房子的价格变化,每当房子价格变化的时候,所有的购房者都可以观察得到.实际上以上的购房者都属于观察者,他们都关注着房子的价格. 如果要想实现观察者模式,则必须依 ...
- spring ObjectFactory
AspectJAwareAdvisorAutoProxyCreator implements PostProcessor postProcessorAfterInitialization(Object ...