2.4优先队列
先介绍两个动作方法。1.下沉 2.上浮
1. 下沉
//下沉 k指的是父节点
private void sink(int k){
//子节点为 2*k,只要子节点 不大于N,即还没有下沉完
while(2*k <= N){
int j = 2*k;
//先比较该元素的两个子节点,如果左节点 小于 右节点,则进行交换,选一个较大的子节点与父节点进行比较
if(j < N && less(j,j+1) ) j++;
//如果 较大的子节点 都小于父节点,就结束 下沉;否则交换。
if(!less(k,j))break;
exch(k,j);
//把刚交换的子节点 换给k,进入下一次的比较
k=j;
}
}
2.上浮
//上浮
private void swim(int k){
//只要k>1,且k/2 为它的父节点,小于它,即:进行交换
while(k>1 &&less(k/2,k)){
exch(k/2,k);
k = k/2;
}
}
优先队列:是一种抽象数据类型。API 见p195, 最重要的操作就是 :
1. 删除最大元素。
2. 插入元素。
具体实现如下:
//仅仅实现了 删除最大的元素(返回最大元素),和使堆有序化
public class MaxPQ<Key extends Comparable<Key>> {
private Key[] pq;//基于堆的完全按二叉树,存储于qp[1...N],qp[0]没有使用
private int N = 0;//计数
//创建数组
public MaxPQ(int maxN){
pq = (Key[])new Comparable[maxN+1];
}
public boolean isEmpty(){
return N==0;
}
public int size(){
return N;
}
public void insert(Key v){
pq[++N] =v;
}
/*
* 删除元素
*
*/
public Key delMax(){
//把根节点 赋给 max,因为它是最大的
Key max = pq[1];
//让最后一个元素 顶替 根元素
exch(1,N--);
pq[N+1] = null;
//下沉它
sink(1);
return max;
}
//下沉 k指的是父节点
private void sink(int k){
//子节点为 2*k,只要子节点 不大于N,即还没有下沉完
while(2*k <= N){
int j = 2*k;
//先比较该元素的两个子节点,如果左节点 小于 右节点,则进行交换,选一个较大的子节点与父节点进行比较
if(j < N && less(j,j+1) ) j++;
//如果 较大的子节点 都小于父节点,就结束 下沉;否则交换。
if(!less(k,j))break;
exch(k,j);
//把刚交换的子节点 换给k,进入下一次的比较
k=j;
}
}
//pq[v]小,pq[m]大
public boolean less(int v, int m ){
return pq[v].compareTo(pq[m])<0;
}
}
//交换
public void exch(int i, int j){
Key t = pq[i];
pq[i]= pq[j];
pq[j]= pq[i];
}
最后:讲一下堆排序;
public static void sort(Comparable[] a){
int N = a.length;
//数组a,使它符合 有序堆----构造有序堆
//k = N/2 为最后的一个父节点,因为N为最后的叶子节点。一次遍历父节点,则是它下沉,使之成为有序堆
for(int k = N/2; k>=1; k--){
sink(a,k,N);
}
//因为1为堆的根节点,为最大。所以先把它(最大的元素)放在最后。sink()再使之成为有序堆。反复直到为空。
while(N>1){
exch(a,1,N--);
sink(a,1,N);
}
}