算法基础三:分治算法---基于二叉堆的优先队列
一、算法描述与分析
堆还有一个作为有效优先队列的应用。优先队列,指的是队列中的元素都被指派了一个优先级,元素按优先级最大(或最小)出队。由于,存储堆的数组的第一个元素就是最大的(或者最小的),所以用堆作为优先队列的元素载体是合适的。
队列有两个基本操作:
- 入队操作ENQUEUE(Q,e),其中参数Q是优先队列,e是要加入队列的元素。
- 出队操作DEQUEUE(Q),它将返回Q中优先级最大(最小)的元素。
下面讨论利用最大堆的最大优先队列Q,假定Q是一个最大堆。
1、入队算法描述与分析
对于入队的操作,我们把要加入的元素放在堆的末尾,然后维护堆的性质——从新的末尾开始,若检测到当前元素的优先级大于其父亲节点元素的优先级,两者互换。ENQUEUE
伪代码描述
ENQUEUE(Q,e)
if heap-size[Q] = length[Q] //堆的空间已经满了(数组没有多余的空间了)
then error "堆上溢"
i <- heap-size[Q] <- heap-size[Q] + 1 //如果堆空间没有满,更新heap-size(已经入堆的元素)
A[heap-size[Q]] <- e //把元素放在队的最后面
while i > 1 and A[PARENT(i)] < A[i] //从新的末尾开始,若检测到当前元素的优先级大于其父亲节点元素的优先级,两者互换
do exchange A[i] <-> A[PARENT(i)]
i <- PARENT(i)
2、出队算法描述与分析
对于出队操作,只要将堆Q中的最大元素(Q[1])“舍弃”:Q[1]的值暂存于max,将Q[heap-size[Q]]赋予Q[1],并使得heap-size减小1.然后维护剩余元素的堆性质,并返回max。
伪代码描述
DEQUEUE(Q)
if heap-size[Q] < 1
then error "堆下溢"
max <- Q[q]
Q[1] <- Q[heap-size[Q]]
heap-size[Q] <- heap-size[Q] - 1
MAX-HEAPIFY (Q,1)
return max
二、自编程序实现版本
1、算法代码
利用上一节开发的程序,来实现本次的优先队列类PrioQueue;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;
public class PrioQueue {
private Vector<Comparable> heap;
private int heapSize;
Comparator comparator;
public PrioQueue(){
heapSize = 0;
heap = new Vector<Comparable>();
comparator = new Greater();
}
public PrioQueue(Comparator comp){
heapSize = 0;
heap = new Vector<Comparable>();
comparator = comp;
}
public void enQueue (Comparable e){
int i = heapSize++;//进入队列加一
heap.add(e);
while ((i>0) && (comparator.compare(heap.get(i),heap.get(LinearList.parent(i))) > 0)){
Collections.swap(heap,LinearList.parent(i),i);
i = LinearList.parent(i);
}
}
public Comparable deQueue(){
if (heapSize<1)
return null;
Comparable top = heap.get(0);//top <- heap[0]
heapSize--;
heap.set(0,heap.get(heapSize)); //heap[0] <- heap[heapSize]
heap.remove(heapSize); //将heap[heapSize]从heap中删除
LinearList.heapify(heap,0,heapSize,comparator);
return top;
}
public boolean empty(){
return heapSize <= 0;
}
}
2、测试代码
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Vector;
public class TestPrioQueue {
public static void main(String[] args) {
Integer a[] = {5,1,9,4,6,2,0,3,8,7},i;
String b[] = {"ChongQing","ShangHai","AoMen","TianJin","BeiJing","XiangGang"};
Double c[] = {8.5,6.3,1.7,9.2,0.5,2.3,4.1,7.4,5.9,3.7};
PrioQueue q = new PrioQueue();
PrioQueue q1 = new PrioQueue(new Less());
PrioQueue q2 = new PrioQueue(new Greater());
for (i=0;i<10;i++){
q.enQueue(a[i]);
q2.enQueue(c[i]);
}
for (i=0;i<6;i++)
q1.enQueue(b[i]);
while (!q.empty())
System.out.print(q.deQueue()+" ");
System.out.println();
while (!q1.empty())
System.out.print(q1.deQueue()+" ");
System.out.println();
while (!q2.empty())
System.out.print(q2.deQueue()+" ");
System.out.println();
}
}
三、Collection Framework的PriorityQueue类
Java提供了一个优先队列类PriorityQueue,该类定义在包Java.util中,它有两个构造方法:默认的构造方法PriorityQueue(),创建一个空的最小优先队列;PriorityQueue (int n, Comparator comparator)使用比较规则comparator创建一个可以容纳n个元素的优先队列
测试代码
import java.util.PriorityQueue;
public class TestPrioQueue_2 {
public static void main(String[] args) {
Integer a[] = {5,1,9,4,6,2,0,3,8,7},i;
PriorityQueue q = new PriorityQueue(10, new Less());
PriorityQueue q1 = new PriorityQueue();
for (i=0;i<10;i++){
q.add(a[i]);
q1.add(a[i]);
}
while (!q.isEmpty())
System.out.print(q.poll() + " ");
System.out.println();
while (!q1.isEmpty())
System.out.print(q1.poll()+" ");
System.out.println();
}
}