堆排序集合了插入排序和归并排序的优点,即时间复杂度为nlogn,同时也具备空间原址性:任何时候都只需要常数个额外的元素空间存储临时变量。
它所采用的(二叉)堆是一个数组,可以看出一个近似的完整二叉树,除了最底层,其他都是充满的,所以我们很容易计算出一个结点i的父结点(i/2)、左右孩子结点(2i,2i+1)。
首先创建一个函数maxHeapify(),它的作用是维护堆的性质,输入为一个数组a和一个下标i,我们假设根结点为left(i)和right(i)的二叉树都是最大堆,但a[i]可能小于其左右子结点,所以要让a[i]的值逐级下降至合适的位置,从而从新构成一个最大堆。在维护最大堆的过程中,只维护heapsize内的结点。
然后我们通过自底向上的方式创建一个最大堆,开始heapsize等于数组长度length,然后将根结点与数组最后一个结点对调,heapsize-1,维护最大堆,然后重复上述操作即可完成排序。
它所采用的(二叉)堆是一个数组,可以看出一个近似的完整二叉树,除了最底层,其他都是充满的,所以我们很容易计算出一个结点i的父结点(i/2)、左右孩子结点(2i,2i+1)。
首先创建一个函数maxHeapify(),它的作用是维护堆的性质,输入为一个数组a和一个下标i,我们假设根结点为left(i)和right(i)的二叉树都是最大堆,但a[i]可能小于其左右子结点,所以要让a[i]的值逐级下降至合适的位置,从而从新构成一个最大堆。在维护最大堆的过程中,只维护heapsize内的结点。
然后我们通过自底向上的方式创建一个最大堆,开始heapsize等于数组长度length,然后将根结点与数组最后一个结点对调,heapsize-1,维护最大堆,然后重复上述操作即可完成排序。
//交换两个结点
public void exchange(int []a,int i,int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
//维护最大堆
public void maxHeapley(int []a,int i,int heapSize){
int left = 2*i + 1;
int right = 2*i + 2;
int maxNum = i;
if((left < heapSize)&&(a[left] > a[i])){
maxNum = left;
}
if((right < heapSize)&&(a[right] > a[maxNum])){
maxNum = right;
}
if(maxNum != i){
exchange(a,i,maxNum);
maxHeapley(a, maxNum,heapSize);
}
}
创建最大堆
public void bulidMaxHeap(int []a){
if((a == null)||(a.length<=1)){
return;
}
for(int i = a.length/2-1;i >= 0;i--){
maxHeapley(a, i, a.length);
}
}
//堆排序
public void heapSort(int a[]){
if((a == null)||(a.length<=1)){
return;
}
bulidMaxHeap(a);
int heapSize = a.length;
for(int i = a.length-1;i > 0;i--){
exchange(a, i, 0);
heapSize --;
maxHeapley(a, 0, heapSize);
}
}