概念
堆排序是选择排序的一种,堆通常是一个可以被看做一棵完全二叉树的数组对象。
堆是一种不稳定的内部排序算法,时间复杂度无论最好,最差,平均都是$log(n)$,此处n表示待排序元素个数。
- 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
- 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;
补充
不稳定排序:数组中相同的元素,在经过排序,前后顺序会发生变化,即不稳定。细节可参照数据结构严蔚敏版。
内部排序:只在内存中进行的排序,不会有数据和磁盘进行交换。
性质
以下假设构造大根堆,则堆必须满足以下要求:
- 堆是一个完全二叉树,这样才能保证根节点i能直接2*i的方式映射到孩子节点
- 根节点必须大于左右孩子节点
步骤
提供一组数据,这组数据为堆对应完全二叉树的层次遍历结果,使用堆排序完成升序排序(构造大根堆)
- 构建大根堆
- 交换堆顶和堆最后一个元素(把此轮最大值放到数组后方,后续只对剩下的无序堆排序,每次排序少一个需要排序的元素)
- 调整剩下的无序堆为有序大根堆:从最后一个非叶子节点,从下往上,从左往右(利用性质一),之后2,3不交替进行,直至需要带排序元素个数为0.
点此链接,可以查看在线效果图
代码
Java版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| package sort.exchange;
import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Scanner;
public class HeapSort { public static void main(String[] args) {
Integer[] arr = {1, 2, 3, 4, 5, 6}; System.out.println("排序前:" + Arrays.toString(arr)); sort(arr); System.out.println("排序前:" + Arrays.toString(arr)); }
public static void sort(Integer[] arr) {
for (int i = arr.length / 2 - 1; i >= 0; i--) { adjustHeap(arr, i, arr.length); }
for (int j = arr.length - 1; j > 0; j--) { int temp = arr[0]; arr[0] = arr[j]; arr[j] = temp; adjustHeap(arr, 0, j-1); }
}
public static void adjustHeap(Integer[] arr, int i, int length) {
int temp = arr[i];
for (int j = i * 2 + 1; j < length; j = j * 2 + 1) { if(j+1<length){ j = arr[j] > arr[j + 1] ? j : j + 1; }
if (arr[j] > temp) {
arr[i] = arr[j];
arr[j] = temp;
i = j; }
else { break; }
} } }
|
学习收获
- 堆排序不稳定。
- 堆排序可以视作完全二叉树。
- 注意Java代码难点部分,
for (int j = i * 2 + 1; j < length; j = j * 2 + 1)
可以先画图理解后,对应索引变化编写代码。