知识要求
需要二叉树、小顶堆、大顶堆的知识。
排序步骤
- 首先先将数组堆化,变成大顶堆。
- 然后将首元array[0]与尾元array[n]替换,接着将首元向下调整,变成array[0,...,n-1]为大顶堆
- 然后将首元array[0]与尾元array[n-1]替换,接着将首元向下调整,变成array[0,...,n-2]为大顶堆
-
·
-
·
-
·
- 然后将首元array[0]与尾元array[1]替换,接着将首元向下调整,变成array[0,1]为大顶堆
- 这时候数组已经排好序了
代码实现
private static void sort(int[] array) {
//先堆化
makeMaxHeap(array);
//将根结点array[0]与最末尾节点array[i]交换,
//这时候只需要根结点array[0]向下调整即可
for(int i=array.length-1; i>0; i--) {
swap(array,0,i);
maxHeapFixDown(array,0,i);
}
}
//堆化
private static void makeMaxHeap(int[] array) {
for(int i=(array.length-2)>>1; i>=0; i--) {
//从最后一个节点开始,每个节点向下调整
//当每个节点都向下调整完,这个数组就堆化了
maxHeapFixDown(array, i, array.length);
}
}
//将array[i]向下调整
private static void maxHeapFixDown(int[] array, int i, int length) {
//寻找到左右孩子
int left = i*2+1;
int right = i*2+2;
//找到左右孩子较大的那个
int max = 0;
/*
* 现在有三种情况,
* 左右孩子都有,
* 只有左孩子,
* 一个孩子都没有
*/
if (right <= length-1) {
max = array[left] >= array[right] ? left : right;
}
else if(left == length-1)
max = left;
else
return;
//将父结点与较大的孩子比较,若父节点更大则无需改变
if(array[i] >= array[max])
return;
//若父节点更小,则需要与max上的数据交换,然后在比较max作为父节点的堆是否为大顶堆
else {
swap(array, i, max);
// 如果根结点比较小的孩子还小,则需要交换他们的位置,然后再向下检查交换过后的数据是否是小顶堆
maxHeapFixDown(array,max,length);
}
}
private static void swap(int[] array, int i, int max) {
int num = array[i];
array[i] = array[max];
array[max] = num;
}
时间复杂度
时间分为两个阶段:建堆和排序。建堆时有个节点需要向下调整,每次最多调整
次,所以建堆需要的时间为
。排序时每个元素都要到根结点上进行向下调整,调整的次数为
,所以排序需要的时间为
。总时间为
。