概念
-
堆是一种特殊的完全二叉树,每个节点的值都大于或等于子节点的值,称为大顶堆,反之,称为小顶堆;注意:没有对节点的左右孩子节点的值做出要求
-
大顶堆特点:arr[i] >= arr[2 * i +1 ] && arr[i] >= arr[2 * i + 2]
-
小顶堆特点:arr[i] <= arr[2 * i +1 ] && arr[i] <= arr[2 * i + 2]
堆排序
-
堆排序是利用堆这一数据结构设计的一种排序算法,堆排序是一种选择排序,他的最坏、最好、平均时间复杂度均为O(nlogn),是一种不稳定排序
基本思想
-
将待排序列构成一个大顶堆
-
此时堆的根结点即为最大值
-
将其与末尾元素交换位置,此时末尾为最大值
-
然后将剩余n-1个元素重新构成堆
-
反复执行上述过程
树的节点特点
-
n0 + n2 = n
-
n0 = n2 + 1
-
2* n2 + 1 = n
-
n2 = (n-1)/2
其中数字代表节点的度
这里直接上代码
public class HeapSort {
/**
* 堆排序: 将待排序列构成一个大顶堆,此时堆的根结点即为最大值,将其与末尾元素交换位置
* 此时末尾为最大值,然后将剩余n-1个元素重新构成堆,反复执行上述过程
* 从小到大排序用大顶堆,反之用小顶堆
* @param arr
* @return
*/
public int[] heapSort(int[] arr) {
// 1. 找到最后一个非叶子结点,即最后一个结点的父节点((arr.length - 1) - 1)/2 == arr.length/2 - 1
// 观察到非叶子结点为倒数1 3 5 7 ...的父节点,其下标为arr.length/2-1 / arr.length/2-2 / arr.length/2-3
int temp;
// 每次长度-1
for (int k = 1 ; k < arr.length ; k++) {
// 节点非叶子节点个数 (arr.length - 1)
for (int i = 0; i <= (arr.length - 1 - k) / 2; i++) {
// 3. 找到下一个非叶子结点进行上述操作,直到根结点(i == 0),因为从下岛上进行交换,所以会打乱,重新进行比较交换
for (int j = (arr.length - k) / 2 - 1; j >= 0; j--) {
// 2. 判断该节点与其左右孩子节点(2*i+1) (2*i+2)进行比较,并交换位置
if (arr[j] < arr[2 * j + 1]) {
temp = arr[j];
arr[j] = arr[2 * j + 1];
arr[2 * j + 1] = temp;
}
if (arr[j] < arr[2 * j + 2]) {
temp = arr[j];
arr[j] = arr[2 * j + 2];
arr[2 * j + 2] = temp;
}
}
}
// 将根与末尾元素交换
temp = arr[0];
arr[0] = arr[arr.length - k];
arr[arr.length - k] = temp;
}
return arr;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// System.out.println("请输入数组长度: ");
// int n = scanner.nextInt();
// int arr[] = new int[n];
// System.out.println("请输入数组元素: ");
// for (int i = 0 ; i < n ; i++){
// arr[i] = scanner.nextInt();
// }
int[] arr = {4 , 6 , 8 , 5 , 9 , 1};
HeapSort heapSort = new HeapSort();
arr = heapSort.heapSort(arr);
for (int i = 0 ; i < arr.length ; i++){
System.out.print(arr[i] + " ");
}
System.out.println();
}
}