← [ BACK_TO_NOTES ]

堆与堆排序(Heap / Heap Sort)

堆的数组表示、heapInsert/heapify,以及堆排序的两种建堆方式。

#algorithm #concept #growing #heap #sort

[!info] related notes 算法面试题型 MOC

堆与堆排序(Heap / Heap Sort)

堆是什么

这里讨论二叉堆:一棵完全二叉树,用数组紧凑表示。优先队列是按优先级取出元素的抽象接口,二叉堆是其常见实现,不是同一层概念;它也不同于运行时内存管理中的堆。

  • 大根堆:父节点 >= 子节点(堆顶是最大值)
  • 小根堆:父节点 <= 子节点(堆顶是最小值)

数组下标关系

对下标 i:

  • parent = floor((i - 1) / 2),只对 i > 0 求父节点
  • left = i * 2 + 1
  • right = i * 2 + 2

两个基本操作

heapInsert(向上调整)

当你在末尾插入新元素后,向上与 parent 交换,直到满足堆性质。

单次复杂度:$O(\log n)$。

heapify(向下调整)

当堆顶变小/变大导致堆性质破坏时,从根向下与更优的子节点交换,直到满足堆性质。

前提是该节点的左右子树已经各自满足堆性质。大根堆选较大的孩子,小根堆选较小的孩子;只修复当前根到叶子的一条路径。单次复杂度 O(log n)。

Java Template (Max-Heap + Heap Sort)

import java.util.*;

public class HeapSort {
    static void heapInsert(int[] arr, int i) {
        while (i > 0 && arr[i] > arr[(i - 1) / 2]) {
            swap(arr, i, (i - 1) / 2);
            i = (i - 1) / 2;
        }
    }

    static void heapify(int[] arr, int i, int size) {
        int l = i * 2 + 1;
        while (l < size) {
            int best = (l + 1 < size && arr[l + 1] > arr[l]) ? (l + 1) : l;
            best = arr[best] > arr[i] ? best : i;
            if (best == i) break;
            swap(arr, best, i);
            i = best;
            l = i * 2 + 1;
        }
    }

    static void heapSortTopDown(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = 0; i < arr.length; i++) heapInsert(arr, i);
        int size = arr.length;
        while (size > 1) {
            swap(arr, 0, --size);
            heapify(arr, 0, size);
        }
    }

    static void heapSortBottomUp(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = arr.length / 2 - 1; i >= 0; i--) heapify(arr, i, arr.length);
        int size = arr.length;
        while (size > 1) {
            swap(arr, 0, --size);
            heapify(arr, 0, size);
        }
    }

    static void swap(int[] arr, int i, int j) {
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
}

堆排序

方案 A:从顶到底插入建堆

依次插入元素,每次 heapInsert。

  • 建堆:$O(n\log n)$

方案 B:从底到顶建堆(Floyd)

从最后一个非叶子节点开始,对每个节点 heapify。

  • 建堆:O(n),因为大多数节点靠近叶子,不是 n 个节点都需要下沉 log n 层

排序阶段

重复:交换堆顶与末尾,缩小 size,再 heapify。

  • 排序:$O(n\log n)$
  • 本例全程迭代,额外空间 O(1),会修改原数组
  • 大根堆的堆顶依次放到末尾,最终得到升序数组;堆本身不保证兄弟节点或整个数组有序
  • 常规堆排序不稳定,相等键的原顺序可能变化
创建于 2026/3/16 更新于 2026/10/7
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本