堆排序
分为两部分来说:一是堆的实现、二是堆的排序
堆的实现:
public class MaxPQ{
private int[] pq;
private int N = 0;
public MaxPQ(int maxN){
pq = new int[maxN+1];
}
public boolean isEmpty(){
return N==0;
}
public boolean size(){
return N;
}
public void insert(int v){
pq[++N] = v;
swim(pq,1,N);
}
public int delMax(){
int max = pq[1]; //从根节点得到最大元素
swap(pq,1,N--); //将其和最后一个节点交换
pq[N+1] = null; //防止对象游离
sink(pq,1,N); //恢复堆的有序性
return max;
}
private void swap(int[] a,int i,int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
//某个节点变得比父节点更大而打破,我们需要交换它和它的父节点來修复堆
private void swim(int[] pq,int lo,int hi){
while(hi>lo&&pq[hi/2]<pq[hi]){//比父节点大,进行调整
swap(pq,hi/2,hi);
hi = hi/2;
}
}
//某个节点比它的两个或一个子节点小,需要交换它和它的子节点来修复堆
private void sink(int[] pq,int lo,int hi){
while(lo*2<=hi){
int j = 2*lo;
if(j<hi&&pq[j]<pq[j+1]) j++;//找到子元素中最大的那个
if(pq[lo]>pq[j]) break;
swap(pq,lo,j);
lo = j;
}
}
}
堆排序分为堆构造和下沉排序两个阶段。
堆构造阶段将原始数组重新组织安排进一个堆中;下沉排序阶段,我们从堆中按递减顺序取出所有元素并得到排序结果(将堆中的最大元素删除,然后放进堆缩小后数组中空出的位置)。
public void sort(int[] a){
int N = a.length;
for(int i=N/2;i>=1;i--){//构造堆
sink(a,i,N); //sink构造子堆
}
while(N>1){
sort(a,1,N--); //将堆中最大元素删除,然后放进堆缩小后数组中空出来的位置
sink(a,1,N); //
}
}