第一步:用给定的数组构造一个大(小)顶堆,在for循环中调用构造顶堆的函数adjustHeap,初始的i=为第一个非叶子节点的下标,然后从底向上调整顶堆。arr代表待排序数组。
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
第二步:调用交换函数swap,交换堆顶和最后一个元素的位置,在进行此次操作之后,此堆不再是大(小)顶堆,此时应该再次调用adjustHeap函数,进行重新构造。
因为堆顶元素已经被交换到最后一个位置,被视为这个数字排序完毕,所以数组的长度要减一,使此数字不参加下次堆的调整。另外,adjustHeap中的第二个参数为0,表示从堆顶开始调整不同于第一次从最右,最底开始。
//2.调整堆结构+交换堆顶元素与末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
构造大顶堆函数如下:构造大小顶堆最核心的思想就是比较子节点和父节点的大小,如果子节点大于父节点那么就需要将子节点赋给父节点,再在for循环结束后,再将存在temp中的父节点的值赋给子节点。
把第一个if中的 arr[k]<arr[k+1]换成arr[k]>arr[k+1]
以及第二个if中的arr[k] >temp换成arr[k]<temp
就是小顶堆,即将数组从大到小排序
public static void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出当前元素i
for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
k++;
}
if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点
arr[i] = arr[k];
i = k;
}else{
break;
}
}
arr[i] = temp;//将temp值放到最终的位置 如果子节点大于父节点 将 父节点的值赋给子节点 和第二个if中的代码,构成交换。
}
交换函数
public static void swap(int []arr,int a ,int b){
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
全部代码如下:
import java.util.Arrays;
public class HeapSort {
public static void main(String []args){
int []arr = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(int []arr){
//1.构建大顶堆
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//2.调整堆结构+交换堆顶元素与末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
}
/**
* 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
* @param arr
* @param i
* @param length
*/
public static void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出当前元素i
for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
k++;
//arr[k]<arr[k+1] 换成arr[k]>arr[k+1] 以及40行的arr[k] >temp换成arr[k]<temp 就是小顶堆
}
if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点
arr[i] = arr[k];
i = k;
}else{
break;
}
}
arr[i] = temp;//将temp值放到最终的位置 如果子节点大于父节点 在此交换
}
/**
* 交换元素
* @param arr
* @param a
* @param b
*/
public static void swap(int []arr,int a ,int b){
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
代码源自网路