在C语言中,堆(Heap)是一个非常重要的数据结构,它主要用于实现优先队列。堆可以被看作是一棵完全二叉树,其中每个父节点的值都大于或等于(最大堆)或小于或等于(最小堆)其子节点的值。这里,我们将主要讨论最大堆的实现和基本原理。
堆的基本操作
堆的主要操作包括:
- 插入(Push/Heapify Up):将一个新的元素插入到堆中,并保持堆的性质。
- 删除最大元素(Pop/Heapify Down):删除堆顶元素(最大元素),并将堆的最后一个元素移到堆顶,然后重新调整堆以恢复其性质。
堆的存储
堆通常使用数组来存储,因为数组可以通过索引快速访问父节点和子节点。对于一个索引为 i
的节点,其父节点的索引是 (i-1)/2
,左子节点的索引是 2*i+1
,右子节点的索引是 2*i+2
。
示例代码
以下是一个简单的最大堆实现示例,包括堆的插入和删除操作:
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void heapifyUp(int arr[], int n, int i) {
while (i > 0 && arr[parent(i)] < arr[i]) {
swap(&arr[parent(i)], &arr[i]);
i = parent(i);
}
}
void heapifyDown(int arr[], int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] > arr[largest])
largest = left;
if (right < n && arr[right] > arr[largest])
largest = right;
if (largest != i) {
swap(&arr[i], &arr[largest]);
heapifyDown(arr, n, largest);
}
}
void insert(int arr[], int *n, int element) {
if (*n >= MAX_SIZE)
return;
arr[*n] = element;
(*n)++;
heapifyUp(arr, *n, *n - 1);
}
int deleteMax(int arr[], int *n) {
if (*n <= 0)
return INT_MIN; // 假设最小可能值是INT_MIN
int popped = arr[0];
arr[0] = arr[*n - 1];
(*n)--;
heapifyDown(arr, *n, 0);
return popped;
}
int parent(int i) {
return (i - 1) / 2;
}
int main() {
int heap[MAX_SIZE] = {0};
int n = 0;
insert(heap, &n, 15);
insert(heap, &n, 10);
insert(heap, &n, 20);
insert(heap, &n, 8);
insert(heap, &n, 12);
printf("Max element is %d\n", deleteMax(heap, &n));
printf("Max element is %d\n", deleteMax(heap, &n));
return 0;
}
注意事项
- 堆的实现非常依赖于数组索引与树节点之间的关系。
- 堆的插入和删除操作都是对数时间复杂度(O(log n)),这使得堆在需要频繁访问最大或最小元素的场景中非常有用。
- 在实际应用中,堆常用于实现堆排序算法,以及作为优先级队列的基础数据结构。