堆排序是基于完全二叉树实现的,一个二叉树其父结点均大于子结点称为大顶堆,可以实现升序排序。堆顶的根结点就是整个序列的最大值,将其与末尾元素交换,末尾就成为最大值。然后将剩余n-1个元素重新构造成一个堆,重复上述操作即可得到升序排序。
注意是从最后一个非叶子结点开始比较得到大顶堆。最后一个非叶子结点的序号为arr.length/2-1。
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
//要求将数组进行升序排序
int[] arr= {0,1,2,3,4,5,6,7,8};
heapSort(arr);
}
//编写一个堆排序的方法
public static void heapSort(int arr[]) {
System.out.println("堆排序");
int temp=0;
/*//分步完成
adjustHeap(arr,1,arr.length);
System.out.println("第一次"+Arrays.toString(arr));//4,9,8,5,6
adjustHeap(arr,0,arr.length);
System.out.println("第二次"+Arrays.toString(arr));//9,6,8,5,4*/
//将无序序列构成一个堆,根据升序降序需求选择大顶堆或者小顶堆
for(int i=arr.length/2-1;i>=0;i--) {
adjustHeap(arr,i,arr.length);
}
//将堆顶元素与末尾元素交换,将最大元素“沉”到数组末端
//重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换,直到整个序列有序
for(int j=arr.length-1;j>0;j--) {
//交换
temp=arr[j];
arr[j]=arr[0];
arr[0]=temp;
adjustHeap(arr,0,j);
}
System.out.println("数组="+Arrays.toString(arr));
}
//将一个数组(二叉树)调整成一个大顶堆
//i表示非叶子结点在数组中索引,length表示对多少个元素继续调整,length逐渐
//减少。
public static void adjustHeap(int[] arr,int i,int length) {
int temp=arr[i];//先取出当前元素,保存在临时变量
//开始调整
//说明:k=i*2+1是i结点的左子结点
for(int k=i*2+1;k<length;k=k*2+1) {
if(k+1<length&&arr[k]<arr[k+1]) {//左子结点的值小于右子结点
k++;//k指向右子结点
}
if(arr[k]>temp) {//子结点大于父结点
arr[i]=arr[k];//把较大的值赋给当前结点
i=k;//i指向k,继续循环比较
}else {
break;//
}
}
//当for循环结束后,我们已经将以i为父结点的树的最大值,放在了最顶(局部)
arr[i]=temp;//将temp放在调整后的位置
}
}