现在位置: 首页 > C 语言数据结构与算法 > 正文

数据结构 - 堆

堆(Heap)是一种特殊的完全二叉树结构,满足堆序性质。堆只保证父子节点之间的大小关系,不要求左右子树之间存在严格的顺序。


堆的定义与存储

堆 (Heap) — 最大堆结构与数组存储

树形视图(最大堆)

15索引0
10索引1
8索引2
53
34
25

数组视图(紧凑存储)

15
[0]
10
[1]
8
[2]
5
[3]
3
[4]
2
[5]

父:(i-1)/2 | 左子:2i+1 | 右子:2i+2

完全二叉树 → 天然适合数组,无指针开销

上浮 Sift Up(插入)O(log n)

新元素放末尾 → 与父比较 → 若大则交换 → 重复至堆顶

下沉 Sift Down(删除堆顶)O(log n)

末尾元素移堆顶 → 与较大子比较 → 若小则交换 → 重复至叶

堆的两种类型:

  • 最大堆(Max Heap):每个父节点 ≥ 子节点,根节点为最大值
  • 最小堆(Min Heap):每个父节点 ≤ 子节点,根节点为最小值

由于堆是完全二叉树,天然适合用数组存储:

节点(索引 i)关系位置(0-based)
父节点parent(i)(i - 1) / 2
左子节点left(i)2 * i + 1
右子节点right(i)2 * i + 2

堆的插入与删除(堆化过程)

实例

#include <stdio.h>

#define MAX 100

/* 最大堆结构 */
struct MaxHeap {
    int arr[MAX];
    int size;  /* 当前元素个数 */
};

void initHeap(struct MaxHeap* h) { h->size = 0; }

void swap(int* a, int* b) { int t = *a; *a = *b; *b = t; }

/* 上浮 (Sift Up):新插入元素从底部向上调整
   与父节点比较,若大于父节点则交换,直到满足堆序 */

void siftUp(struct MaxHeap* h, int idx) {
    while (idx > 0) {
        int parent = (idx - 1) / 2;
        if (h->arr[idx] <= h->arr[parent]) break;
        swap(&h->arr[idx], &h->arr[parent]);
        idx = parent;
    }
}

/* 插入:先将元素放在末尾,再上浮调整 O(log n) */
void insert(struct MaxHeap* h, int value) {
    if (h->size >= MAX) return;
    h->arr[h->size] = value;
    siftUp(h, h->size);
    h->size++;
}

/* 下沉 (Sift Down):从根向下调整
   与较大的子节点比较,若小于则交换,直到满足堆序 */

void siftDown(struct MaxHeap* h, int idx) {
    while (1) {
        int largest = idx;
        int left = 2 * idx + 1;
        int right = 2 * idx + 2;

        if (left < h->size && h->arr[left] > h->arr[largest])
            largest = left;
        if (right < h->size && h->arr[right] > h->arr[largest])
            largest = right;

        if (largest == idx) break;
        swap(&h->arr[idx], &h->arr[largest]);
        idx = largest;
    }
}

/* 删除堆顶(最大值):将末尾元素移到顶部,再下沉调整 O(log n) */
int extractMax(struct MaxHeap* h) {
    if (h->size == 0) return -1;
    int maxVal = h->arr[0];
    h->arr[0] = h->arr[--h->size];  /* 末尾元素移到顶部 */
    siftDown(h, 0);                 /* 下沉调整 */
    return maxVal;
}

int main() {
    struct MaxHeap h;
    initHeap(&h);

    int vals[] = {3, 10, 5, 8, 2, 15};
    for (int i = 0; i < 6; i++) insert(&h, vals[i]);

    printf("依次取出最大值: ");
    while (h.size > 0) {
        printf("%d ", extractMax(&h));
    }
    printf("\n");  /* 输出: 15 10 8 5 3 2 (降序) */
    return 0;
}

应用场景

场景说明
优先队列堆是优先队列最常用的底层实现
堆排序O(n log n) 原地排序算法(第 18 章详讲)
Top K 问题用最小堆维护前 K 个最大元素