堆排序思路:
- 将需要排列的数组造成大顶堆(此时堆顶根节点为最大值)
- 将最大值与数组末尾元素进行交换
- 再次将n-1个元素造堆并进行交换,循环1-3
注:因为第二步之后的堆只有根节点不符合大顶堆规定,所以第三步中造堆不需要从下往上,只需从根节点开始。
造堆思路:(length为需要排序的长度)
- 找到第一个非叶子节点length/2 -1设为i
- 若i的右子节点存在,将其与左子节点比较,较大的设为j
- 将arr[i]与arr[j]进行交换
- i=j(i指针下移到j子节点)
- 循环2-4
- 处理下一个非叶子节点length/2 -1 -1 ,循环2-6 , 直到处理完所以非叶子节点
代码实现:
package Sort;
import java.util.Arrays;
//堆排序(树的实际应用,从下往上,从左往右)
//利用大顶堆找到最大值,将最大值与最后元素进行交换,反复
public class HeapSort {
public static void main(String[] args) {
int arr[] = {4,6,8,5,9,-999,-1,7};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
/**
* 堆排序实现方法(升序)
*/
public static void heapSort(int [] arr){
//1.将数组造为大顶堆
//第一个非叶子节点算法 length /2 -1
for (int i = arr.length/2 - 1; i >= 0 ; i--) {
adjustHeap(arr,i,arr.length);
}
//2.将最大值与最后元素交换
for (int i = arr.length-1; i > 0; i--) {
int temp =arr[0];
arr[0] = arr[i];
arr[i] = temp;
//3.再次造堆,因为此时只有根节点不符合大顶堆,其余子树皆符合
//所以这时只需要从根节点造堆
adjustHeap(arr,0,i);
}
}
/**
* 将数组转换为大顶堆
* @param arr 需要转换的数组
* @param i 从该节点开始转换大顶堆,即为第一个需要处理的非叶子节点
* @param length 需要转换的个数(找到一个最大值后应,减小1)
*/
public static void adjustHeap(int [] arr , int i , int length){
int temp = arr[i];//存储当前节点的值
//比较i节点的左右节点大小
for (int j = 2*i+1; j < length ; j = j*2+1) {
if (j+1 < length && arr[j] < arr[j+1]){
//左子节点小于右子节点,令j指向右子节点
j++;
}
if (temp < arr[j]) {
//子节点大于父节点,交换
arr[i] = arr[j];
arr[j] = temp;
i = j ; //让指针i下移,循环比较原来i的子树
}else {
break;
}
}
}
}
运行结果符合预期,为:
[-999, -1, 4, 5, 6, 7, 8, 9]