堆排序也是根据比较来排序的。堆排序效率很高的,时间复杂度为O(nlgn),因为是利用二叉树索引来进行建堆。
堆包括大顶堆和小顶堆两种。
堆排序包括3步:建堆;整堆;取值。
建堆:
通过数组中的下标来建立索引是数组中的数值在纵向看来是一个二叉树——时间复杂度为O(lgn);
然后从后向前 对非叶子节点进行整堆——(O(n))。
整堆:
通过 比较父节点与左右孩子节点数值的大小,来交换大(小)的值,达到从上到下 父节点的值大(小)于左右孩子节点的值。
堆排序在根据上述建好的堆 依次 获得 最大(小)的根节点的值再把 数组长度减1,这样就得到有序的数组了。
取值:
每次整堆后取根植,即可得有序数组。
下面看看代码:
public class HeapSort { // 这里使用的是大顶堆
public static void swap(int [] a,int i,int j){
int temp = a[i];
a[i] = a[j];
a[j]= temp;
}
public static void buildHeap(int [] a){
int len = a.length;
for(int i = (len/2)-1;i>=0;i--){ //数组下标 从0开始 需 -1
fixHeap(a,i);
}
}
public static void fixHeap(int [] a,int i){ // 注意 数组从0开始时 是 left = 2i+1 ; 要是处理后从1开始时 应该为 left = 2i
int left = 2*i+1;
int right = left+1;
int max = i; // max 标记 father, left, right 3者较大者
if(left<=a.length-1 && a[left]>a[max]){
max = left;
}
if(right<=a.length-1 && a[right]>a[max]){
max = right;
}
if(i!=max){ // 若是father 比 left 或者right 小的话 则 一直向下整堆 使下面始终保持堆的性质
swap(a,i,max);
fixHeap(a,max);
}
}
public static int [] sort(int [] a){
int len = a.length-1;
buildHeap(a);
int [] b = new int [a.length]; // 因为数组是没办法长度-1的 所以 不能获得根数值后 减少长度继续 整堆 这里用b[]来存储根数值
int j=0;
for(int i=len;i>=0;i--){
b[j++] = a[0];
a[0] = -1; // 将a[0] 变成最小的值 -1(仅供参考) 然后就能继续进行整堆 始终能找出剩下数值中最大的了。
fixHeap(a,0);
}
return b;
}
public static void main(String[] args) {
int [] a = {3,2,6,4,9,5,0,1,7,8};
for(int i:a){
System.out.print(i + " ");
}
System.out.println();
a = sort(a);
for(int i:a){
System.out.print(i + " ");
}
}
}
结果不言而喻,肯定能排序的。