堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:

  1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
  2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

堆排序的平均时间复杂度为 Ο(nlogn)。

1. 算法步骤

  1. 将待排序序列构建成一个堆 H[0……n-1],根据(升序降序需求)选择大顶堆或小顶堆;
  2. 把堆首(最大值)和堆尾互换;
  3. 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
  4. 重复步骤 2,直到堆的尺寸为 1。

    2. 动图演示

    堆排序 - 图1

    3. Java 代码实现

    1. private static void heapSort(int[] arr) {
    2. // 原地建堆
    3. int heapSize = arr.length;
    4. for (int i = (heapSize >> 1) - 1; i >= 0; i--) {
    5. siftDown(arr, i, heapSize);
    6. }
    7. while (heapSize > 1) {
    8. //交换堆顶元素和尾部元素,heapSize--
    9. swap(arr, 0, --heapSize);
    10. //对0位置siftDown,恢复堆的性质
    11. siftDown(arr, 0, heapSize);
    12. }
    13. }
    14. private static void siftDown(int[] array, int index, int heapSize) {
    15. Integer element = array[index];
    16. int half = heapSize >> 1;
    17. // index必须是非叶子节点
    18. while (index < half) {
    19. // 默认是左边跟父节点比
    20. int childIndex = (index << 1) + 1;
    21. Integer child = array[childIndex];
    22. int rightIndex = childIndex + 1;
    23. // 右子节点比左子节点大
    24. if (rightIndex < heapSize && array[rightIndex] > child) {
    25. child = array[childIndex = rightIndex];
    26. }
    27. // 大于等于子节点
    28. if (element >= child) {
    29. break;
    30. }
    31. array[index] = child;
    32. index = childIndex;
    33. }
    34. array[index] = element;
    35. }