堆的特性
完全二叉树,除最后一层节点不需要是满的,其他从左到右都是满的。最后一层不满时,必须遵循“左满右不满”。
通常是用数组实现的
堆排序
首先,创建堆,根据堆的定义,根节点大于两个子节点的叫大根堆(小于则叫小根堆)。然后,利用下层算法,实现删除根节点的方法来实现排序。
时间复杂度
O(nlogn)
代码示例(此处是以大根堆来建立的堆排序):
public class HeapSort {
private static boolean less(Comparable[] heap,int i,int j){
return heap[i].compareTo(heap[j])<0;
}
private static void swap(Comparable[] heap,int i,int j){
Comparable t=heap[i];
heap[i]=heap[j];
heap[j]=t;
}
private static void createHeap(Comparable[] source,Comparable[] heap){
/*
先将数组元素复制到heap中,形成未排序的堆
再将堆中元素从长度的一半开始,到索引1处进行下沉
*/
System.arraycopy(source,0,heap,1,source.length);
for (int i=(heap.length)/2;i>0;i--){
sink(heap,i,heap.length-1);
}
}
public static void sort(Comparable[] source){
//创建一个堆数组,长度是原数组长度+1,因为堆数组的第一个索引不存放任何元素
Comparable[] heap = new Comparable[source.length+1];
//通过数组建立堆
createHeap(source,heap);
//定义一个变量来标志堆中的最大索引
int i=heap.length-1;
//通过循环,来交换堆顶和最大索引处的值,将最大值放至最大索引处,不参加下一次循环
while (i!=1){
//交换
swap(heap,1,i);
/*
交换完毕,通过下沉算法将剩下元素中的最大值换到堆顶,0~(--i)是指下沉范围
减掉1是为了让最大索引处不参加下沉,因为它已经是最大值了
*/
sink(heap,1,--i);
}
/*
通过以上过程,此时heap堆中数据已经有序,需将heap复制到原数组source中
*/
System.arraycopy(heap,1,source,0,source.length);
}
public static void sink(Comparable[] heap,int target,int range){
int max;
while (2*target<=range){
if (2*target+1<=range){
if (less(heap,2*target,2*target+1)){
max=2*target+1;
}else {
max=2*target;
}
}else {
max=2*target;
}
if (!less(heap,target,max)){
break;
}
swap(heap,target,max);
target=max;
}
}
}