文章图片
一、什么是优先队列?和普通队列有什么区别?优先队列就是一个元素带有权值(priority)的队列,这个权值又叫做优先级,入队和普通队列一样入队,出队按照权值的大小进行优先出队。权值最小的元素先出队的叫做最小优先队列,权值最大的元素先出队的叫做最大优先队列。
二、优先队列和堆有什么关系?优先队列就是堆吗?优先队列和堆是不一样的数据结构,但是它们的概念相似,堆主要就是用来实现优先队列的,相近的分类有最小堆和最大堆。一般是使用最小堆实现最小优先队列,使用最大堆实现最大优先队列,无论哪一种堆,实现方式都是相似的,另外堆的种类有很多种,如二叉堆、左式堆、斐波那契堆、二项堆等,因此本文说的最小堆和优先队列差不多是一个意思,实现最小堆也就是实现最小优先队列,准确的来说,我们是使用最小堆来实现优先队列。如下图是一个最小二叉堆:
文章图片
三、优先队列有什么作用?优先队列的作用非常多,它的主要特征是按照优先级的大小进行优先出队。优先队列结合其它算法可以实现取得最优值,而且时间界也比较好,标准操作的一般时间为O(n)。例如贪婪算法中可以使用优先队列,Dijkstra算法也属于贪婪算法,其中可以使用优先队列按照距离的大小对顶点进行储存。相似的,A*算法和D*算法也可以使用优先队列,可以大大降低寻路时间。另外,在回溯算法和分支限界法都也可以使用优先队列,一般来说,联机算法中的排序操作或取优操作都可以使用优先队列。
四、Java如何用数组实现优先队列?
文章图片
如上图,是一个逻辑形式的二叉堆以及相应的数组,数组索引和二叉堆中的元素一一对应,你可以发现第i个结点的父结点索引为(i-1)/2,左儿子索引为2*i+1,右儿子索引为2*i+2,根据这个规律,我们可以使用数组表示一个二叉堆,也就是最小堆或最小优先队列,下面我们使用Java来实现一个优先队列。
首先我们希望,这个优先队列可以储存任何类型的数据,所以这里使用泛型T,并且因为是优先队列,所以需要到T获取权值,我们让它实现一个接口:
public interface TypeInterface {// 获取权值或优先级
long getKey();
// 设置权值或优先级
void setKey(long key);
}
【如何实现优先队列(Java使用数组实现最小堆和优先队列)】之后在优先队列的操作中,需要使用权值的时候可以使用getKey获取,更改权值使用SetKey。优先队列的设计中,你可以直接使用一个T数组,但是注意要设计一个capacity数组容量,这里不使用T数组,而是使用一个ArrayList,和数组是一样的,只是没有上界限制,完全实现代码如下:
// Java实现优先队列,最小堆
public class PriorityQueue<
T extends TypeInterface>{private int size;
private ArrayList<
T> array;
// 优先队列构造函数
public PriorityQueue() {
this.size = 0;
this.array = new ArrayList<
>();
}// 使用一个数组构建一个优先队列
public PriorityQueue(ArrayList<
? extends T> list){
this.size = list.size();
this.array = new ArrayList<
>(list);
}// 检查优先队列是否已空
public boolean isEmpty(){
return this.size == 0;
}// 获取父结点位置
private int parent(int i){
return (i - 1) / 2;
}// 获取左儿子位置
private int left(int i){
return 2 * i + 1;
}// 获取右儿子位置
private int right(int i){
return 2 * i + 2;
}private void swap(int i, int j){
T temp = array.get(i);
array.set(i, array.get(j));
array.set(j, temp);
}// 往队列中添加元素
public void push(T value){
if(value =http://www.srcmini.com/= null)
throw new NullPointerException();
this.size++;
int i = this.size - 1;
array.add(i, value);
// 上滤
while(i != 0 &
&
array.get(i).getKey() <
array.get(parent(i)).getKey()){
swap(i, parent(i));
i = parent(i);
}
}// 下滤
private void heapify(int i){
int left = left(i);
int right = right(i);
int small = i;
if(left <
this.size &
&
array.get(left).getKey() <
array.get(i).getKey())
small = left;
if(right <
this.size &
&
array.get(right).getKey() <
array.get(small).getKey())
small = right;
if(small != i){
swap(i, small);
heapify(small);
}
}// 从堆顶取出一个元素
public T pop(){
if(this.isEmpty())
return null;
if(this.size == 1){
T v = array.get(0);
this.size--;
return v;
}
T value = array.get(0);
array.set(0, array.get(this.size - 1));
this.size--;
heapify(0);
return value;
}// 根据数据索引降低关键字的值到value
public void decreaseKey(int i, long value){
if(this.isEmpty() || i>= this.size)
return;
array.get(i).setKey(value);
// 上滤
while(i != 0 &
&
array.get(i).getKey() <
array.get(parent(i)).getKey()){
swap(i, parent(i));
i = parent(i);
}
}// 根据索引删除一个数据
public void delete(int i){
if(this.isEmpty() || i >= this.size)
return;
this.decreaseKey(i, Integer.MIN_VALUE);
this.pop();
}// 快速构建一个堆
public void buildHeap(){
if(this.isEmpty())
return;
for(int i = this.size / 2;
i >= 0;
i--)
heapify(i);
}}
五、Java优先队列的使用首先如果我们要将一个数据添加到优先队列中,需要保证这个类实现了上面的TypeInterface接口,这里给出的例子为Lengua类,如下:
public class Lengua implements TypeInterface{private long id;
private String name;
public Lengua(long id, String name) {
this.id = id;
this.name = name;
}@Override
public long getKey() {
return this.id;
}@Override
public void setKey(long key) {
this.id = key;
}public long getId() {
return id;
}public void setId(long id) {
this.id = id;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}
}
最后,下面是就是这个优先队列的使用和调用实例,第一个例子是属于联机算法的例子,也就是在算法执行过程中,获取一个数据添加一个,第二个例子属于脱机算法,也就是已知所有的数据的情况下,构建一个优先队列,下面是完整调用源码:
// 例子1
PriorityQueue<
Lengua> heap = new PriorityQueue<
>();
Lengua espanol = new Lengua(90, "espanol");
Lengua chino = new Lengua(50, "chino");
Lengua italiano = new Lengua(48, "italiano");
Lengua frances = new Lengua(31, "frances");
Lengua aleman = new Lengua(29, "aleman");
heap.push(espanol);
heap.push(chino);
heap.push(italiano);
heap.push(frances);
heap.push(aleman);
heap.decreaseKey(3, 16);
while (!heap.isEmpty()){
Lengua lengua = heap.pop();
System.out.println(lengua.getId() + "" + lengua.getName());
}System.out.println();
// 例子2
ArrayList<
Lengua> list = new ArrayList<
>();
list.add(espanol);
list.add(chino);
list.add(italiano);
list.add(frances);
list.add(aleman);
PriorityQueue<
Lengua> h = new PriorityQueue<
>(list);
h.buildHeap();
while (!h.isEmpty()){
Lengua lengua = h.pop();
System.out.println(lengua.getId() + "" + lengua.getName());
}
推荐阅读
- Windows Office专业版2016双击激活工具下载和完全安装教程
- wordpress个人博客主题BuddyPress最新中文版在线社区系统社交网站免费下载
- 解决问题(Failed to load resource the server responded with a status of 404 (Not Found))
- 解决Vue错误([Vue warn] Error in render RangeError Invalid array length)
- 解决Vue问题([Vue warn] Avoid mutating a prop…Prop being mutated list (found in component ))
- 解决Vue问题(Uncaught ReferenceError Vue is not defined)
- 解决vue-cli安装错误(npm ERR! A complete log of this run can be found in npm ERR!)
- 前端CSS(实现CSS集合)
- PHP date_default_timezone_set()函数用法详解