Java的PriorityQueue
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6538654.html
优先队列实质上就是数据结构中的最小堆,而堆从概念图来看类似于一棵二叉树,从具体实现来说就是一个具有特别规律的数组,即:数组一个元素相当于堆中一个结点,而其左子结点、右子结点、父结点可以通过下标规律求出:
leftNo = parentNo*2+1
rightNo = parentNo*2+2
parentNo = (nodeNo-1)/2
这样,我们就可以看出:PriorityQueue实际上就是一个以某种比较关系来实现的最小堆,用数组来存放这个堆。PriorityQueue的创建、元素的增加、获取、删除都是对这个堆的操作,即对这个数组的操作。
一:创建优先队列
创建优先队列时,实际上就是新建了一个数组,默认大小11。
private transient Object[] queue; private static final int DEFAULT_INITIAL_CAPACITY = 11;
二:增加元素
add(E e)
和offer(E e)
都是向优先队列中插入元素,只是前者在插入失败时抛出异常,后者会返回false
。
类似于数据结构中最小堆的操作:插入元素时,先插入成为堆的最后一个叶结点,然后根据比较关系把新结点往上调整,直到交换到合适位置。
//offer(E e)
public boolean offer(E e) {
if (e == null)//不允许放入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;
} //siftUp()
private void siftUp(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;//parentNo = (nodeNo-1)/2
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)//调用比较器的比较方法:这里的比较可以是元素的自然顺序,也可以是依靠比较器的顺序(自定义优先级)
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}
三:获取队首
element()
和peek()
都是获取但不删除队首元素,当方法失败时前者抛出异常,后者返回null
。由于堆用数组表示,根据下标关系,0
下标处的那个元素既是堆顶元素。所以直接返回数组0
下标处的那个元素。
//peek()
public E peek() {
if (size == 0)
return null;
return (E) queue[0];//0下标处的那个元素就是最小的那个
}
四:队首出队
remove()
和poll()
都是获取并删除队首元素,当方法失败时前者抛出异常,后者返回null
。由于删除操作会改变队列的结构,为了重新选出队首,需要对堆进行调整。
public E poll() {
if (size == 0)
return null;
int s = --size;
modCount++;
E result = (E) queue[0];//0下标即为队首
E x = (E) queue[s];//把堆尾结点赋值给队首,令堆尾结点为null,相当于队首出队了
queue[s] = null;
if (s != 0)
siftDown(0, x);//原理堆尾的结点现在位于堆顶,需要调整位置,交换到合适位置上,而与它进行交换的结点自然就会上升为堆顶,即队首
return result;
} //siftDown()
private void siftDown(int k, E x) {
int half = size >>> 1;
while (k < half) {
//首先找到左右孩子中较小的那个,记录到c里,并用child记录其下标
int child = (k << 1) + 1;//leftNo = parentNo*2+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;//然后用c取代原来的值
k = child;
}
queue[k] = x;
}
五:删除队中元素
remove(Object o)
方法用于删除队列中跟o
相等的某一个元素。由于删除操作会改变队列结构,所以要进行调整堆的结点位置:1. 删除的是最后一个元素。直接删除即可,不需要调整。2. 删除的不是最后一个元素,则把堆尾的结点赋值给所删除元素的下标,再令堆尾为null(相当于删除了当前元素),最后位于当前位置的堆尾结点位置调整即可。
//remove(Object o)
public boolean remove(Object o) {
//通过遍历数组的方式找到第一个满足o.equals(queue[i])元素的下标
int i = indexOf(o);
if (i == -1)
return false;
int s = --size;
if (s == i) //情况1
queue[i] = null;
else {
E moved = (E) queue[s];
queue[s] = null;
siftDown(i, moved);//情况2
}
return true;
} //siftDown()
private void siftDown(int k, E x) {
int half = size >>> 1;
while (k < half) {
//首先找到左右孩子中较小的那个,记录到c里,并用child记录其下标
int child = (k << 1) + 1;//leftNo = parentNo*2+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;//然后用c取代原来的值
k = child;
}
queue[k] = x;
}
Java的PriorityQueue的更多相关文章
- java中PriorityQueue优先级队列使用方法
优先级队列是不同于先进先出队列的另一种队列.每次从队列中取出的是具有最高优先权的元素. PriorityQueue是从JDK1.5开始提供的新的数据结构接口. 如果不提供Comparator的话,优先 ...
- 《转》JAVA中PriorityQueue优先级队列使用方法
该文章转自:http://blog.csdn.net/hiphopmattshi/article/details/7334487 优先级队列是不同于先进先出队列的另一种队列.每次从队列中取出的是具有最 ...
- 【转】java中PriorityQueue优先级队列使用方法
优先级队列是不同于先进先出队列的另一种队列.每次从队列中取出的是具有最高优先权的元素. PriorityQueue是从JDK1.5开始提供的新的数据结构接口. 如果不提供Comparator的话,优先 ...
- java 中PriorityQueue优先级队列使用方法
1.前言 优先级队列是不同于先进先出队列的另一种队列.每次从队列中取出的是具有最高优先权的元素. PriorityQueue是从JDK1.5开始提供的新的数据结构接口. 如果想实现按照自己的意愿进行优 ...
- Java中PriorityQueue详解
Java中PriorityQueue通过二叉小顶堆实现,可以用一棵完全二叉树表示.本文从Queue接口函数出发,结合生动的图解,深入浅出地分析PriorityQueue每个操作的具体过程和时间复杂度, ...
- Java Collection - PriorityQueue 优先队列
总结 优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素,C++的优先队列每次取最大元素).这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序(na ...
- Java优先队列PriorityQueue的各种打开方式以及一些你不知道的细节
目录 Java优先队列PriorityQueue的各种打开方式以及一些你不知道的细节 优先队列的默认用法-从小到大排序 对String类用优先队列从大到小排序 通过自定义比较器对自定义的类进行从小到大 ...
- java之中PriorityQueue实现原理(具有优先级的队列)
使用大顶堆无限制大小.如果用顺序表实现,插入的时候麻烦,如果用链表(无序)实现得到最大优先级数据的时候麻烦.使用堆可以使两者得到中和.Lucene使用小顶堆定长实现,对于大量数据处理有利.
- Java中的队列Queue,优先级队列PriorityQueue
队列Queue 在java5中新增加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口. Queue使用时要尽量避免Collecti ...
随机推荐
- Java并发编程的艺术(十二)——线程安全
1. 什么是『线程安全』? 如果一个对象构造完成后,调用者无需额外的操作,就可以在多线程环境下随意地使用,并且不发生错误,那么这个对象就是线程安全的. 2. 线程安全的几种程度 线程安全性的前提:对『 ...
- Easyui layout设置满屏效果
html文件: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" ...
- Petri网
Petri网是一种适合于系统描述和分析的数学模型,主要描述异步和并发关系.(或者Petri网是对离散并行系统的数学表示,适用于描述异步的,并发的计算机系统模型.) Petri网模型自然,直观,简单易懂 ...
- jQuery中attr和prop方法的区别说明
jquery中attr和prop的基本区别可以理解为:如果是内置属性,建议用prop,如果是自定义的建议用attr. 例如 <input type=check node=123 id=ck & ...
- spring mvc 返回乱码SpringMVC使用@ResponseBody注解返回中文字符串乱码的问题
原文地址:https://www.cnblogs.com/fzj16888/p/5923232.html 先说一下我的经历,以及解决问题的而过程. 在使用SpringMVC的时候,最开始的时候在配置文 ...
- 奇怪吸引子---Bouali
奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...
- 算法: skiplist 跳跃表代码实现和原理
SkipList在leveldb以及lucence中都广为使用,是比较高效的数据结构.由于它的代码以及原理实现的简单性,更为人们所接受. 所有操作均从上向下逐层查找,越上层一次next操作跨度越大.其 ...
- 断开所有的SMB连接的批处理
备用 @ECHO OFF ECHO ===Check how many SMB shares that already connected=== net use ECHO ===Disconnect ...
- 什么是Platform Services Controller
Platform Services Controller (PSC) is a component of the VMware Cloud Infrastructure Suite. PSC deal ...
- adb 环境配置 常用命令 总结
配置环境变量 右键我的电脑 -> 属性 -> 高级 -> 环境变量 -> Path 在Path中添加Android SDK安装路径中 adb.exe 的路径,例如[\sdk\p ...