1. 什么是堆?
堆(Heap)是一种特殊的树形数据结构,通常用于实现优先队列。它分为最大堆(Max Heap)和最小堆(Min Heap),具有以下特性:
- 最大堆:父节点的值大于或等于任何一个子节点的值。
- 最小堆:父节点的值小于或等于任何一个子节点的值。
在堆中,树的每个节点的值都必须满足堆的性质。
2. 堆的结构和性质
堆通常是一棵完全二叉树,其特性决定了它的用途和性能:
- 完全二叉树:除了最底层,其他每一层的节点都被填满,且最底层从左到右填充。
3. 应用场景
堆在计算机科学中有许多重要应用:
- 优先队列:基于堆实现,能够以O(log n)的时间复杂度获取和删除具有最高(或最低)优先级的元素。
- 堆排序:一种原地排序算法,利用堆的性质进行排序。
- 调度算法:在作业调度、内存管理等领域中有广泛应用。
4. 使用C语言实现最大堆
下面是一个使用C语言实现最大堆的示例代码,
主要操作函数的步骤:
-
插入元素 (
insertMaxHeap
):- 将新元素插入到堆的末尾。
- 自下而上地调整堆,确保满足最大堆的性质,即父节点的值始终大于或等于其子节点的值。
-
最大堆的自上而下调整 (
maxHeapify
):- 给定一个节点的索引,将该节点及其子树调整为最大堆。
- 比较节点与其子节点的值,将最大值作为父节点,递归向下调整直至满足最大堆性质。
-
访问堆顶元素 (
peek
):- 返回堆顶元素,即最大值(最大堆)或最小值(最小堆),但不删除该元素。
- 确保堆不为空,否则返回特定值表示空堆状态。
-
删除堆顶元素 (
extractMax
):- 从堆中删除堆顶元素,并返回该元素的值。
- 将堆的最后一个元素移动到堆顶,然后自上而下地调整堆,以维持最大堆的性质。
#include <stdio.h>
#include <stdlib.h>
#define MAX_HEAP_SIZE 100
// 定义最大堆结构
typedef struct {
int* array; // 存放堆元素的数组
int size; // 堆中当前元素的数量
int capacity; // 堆的容量
} MaxHeap;
// 创建一个新的最大堆
MaxHeap* createMaxHeap(int capacity) {
MaxHeap* heap = (MaxHeap*)malloc(sizeof(MaxHeap)); // 分配堆结构的内存空间
if (heap == NULL) {
perror("Failed to allocate memory for heap");
return NULL;
}
heap->capacity = capacity; // 设置堆的容量
heap->size = 0; // 当前堆中没有元素
heap->array = (int*)malloc(capacity * sizeof(int)); // 分配存放元素的数组空间
if (heap->array == NULL) {
perror("Failed to allocate memory for heap array");
free(heap); // 如果内存分配失败,释放堆的结构内存
return NULL;
}
return heap; // 返回创建好的最大堆
}
// 交换堆中两个节点的值
void swap(int* a, int* b) {
int temp = *a; // 临时变量存储*a的值
*a = *b; // 将*b的值赋给*a
*b = temp; // 将temp的值赋给*b
}
// 最大堆的自上而下调整(向下调整)
void maxHeapify(MaxHeap* heap, int index) {
int largest = index; // 假设最大的元素在根节点
int left = 2 * index + 1; // 左子节点的索引
int right = 2 * index + 2; // 右子节点的索引
// 找到左右子节点中值最大的节点
if (left < heap->size && heap->array[left] > heap->array[largest])
largest = left;
if (right < heap->size && heap->array[right] > heap->array[largest])
largest = right;
// 如果最大值不是当前节点,交换并继续向下调整
if (largest != index) {
swap(&heap->array[index], &heap->array[largest]);
maxHeapify(heap, largest);
}
}
// 插入一个新元素到最大堆中
void insertMaxHeap(MaxHeap* heap, int value) {
if (heap->size >= heap->capacity) { // 如果堆已满,不能再插入更多元素
printf("Heap is full, can't insert more elements.\n");
return;
}
// 将新元素插入到堆的末尾
int index = heap->size; // 新元素的索引位置
heap->array[index] = value; // 将新元素放入堆中
heap->size++; // 堆的大小加1
// 自下而上进行堆的调整
int parent = (index - 1) / 2; // 新元素的父节点索引
while (index > 0 && heap->array[index] > heap->array[parent]) { // 如果新元素大于父节点的值,进行交换
swap(&heap->array[index], &heap->array[parent]); // 交换新元素和父节点的值
index = parent; // 更新索引为父节点索引
parent = (index - 1) / 2; // 更新父节点索引
}
}
// 访问堆顶元素(最大值)
int peek(MaxHeap* heap) {
if (heap->size <= 0) { // 如果堆为空
printf("Heap is empty, no elements to peek.\n");
return -1; // 返回一个特定的值表示错误或空堆情况
}
return heap->array[0]; // 返回堆顶元素(最大值)
}
// 获取堆的元素数量
int size(MaxHeap* heap) {
return heap->size; // 返回堆中当前元素的数量
}
// 判断堆是否为空
int isEmpty(MaxHeap* heap) {
return heap->size == 0; // 如果堆中元素数量为0,返回1(真),否则返回0(假)
}
// 从最大堆中删除并返回堆顶元素
int extractMax(MaxHeap* heap) {
if (heap->size <= 0) { // 如果堆为空,无法删除元素
printf("Heap is empty, no elements to extract.\n");
return -1;
}
// 取出堆顶元素(最大元素)
int max = heap->array[0]; // 堆顶元素(最大元素)
heap->array[0] = heap->array[heap->size - 1]; // 将最后一个元素移到堆顶
heap->size--; // 堆的大小减1
// 自上而下进行堆的调整
maxHeapify(heap, 0);
return max; // 返回被删除的最大元素
}
// 打印输出堆的内容
void printHeap(MaxHeap* heap) {
printf("Max Heap contents: "); // 输出提示信息
for (int i = 0; i < heap->size; ++i) { // 遍历堆中的所有元素
printf("%d ", heap->array[i]); // 打印每个元素的值
}
printf("\n"); // 换行
}
// 释放最大堆的内存
void destroyMaxHeap(MaxHeap* heap) {
if (heap != NULL) { // 如果堆结构不为空
free(heap->array); // 释放存放元素的数组内存
free(heap); // 释放堆结构内存
}
}
int main() {
MaxHeap* heap = createMaxHeap(MAX_HEAP_SIZE); // 创建一个最大堆
// 插入一些元素到最大堆中
insertMaxHeap(heap, 5); // 插入元素5
insertMaxHeap(heap, 3); // 插入元素3
insertMaxHeap(heap, 8); // 插入元素8
insertMaxHeap(heap, 1); // 插入元素1
insertMaxHeap(heap, 10); // 插入元素10
// 打印输出当前堆的内容
printHeap(heap); // 打印当前堆的元素
// 使用peek()访问堆顶元素(最大值)
int top = peek(heap); // 访问堆顶元素
printf("Top element of heap: %d\n", top); // 打印堆顶元素
// 打印当前堆的元素数量
printf("Heap size: %d\n", size(heap)); // 打印堆的元素数量
// 检查堆是否为空
if (isEmpty(heap)) { // 如果堆为空
printf("Heap is empty.\n"); // 输出堆为空的信息
}
else {
printf("Heap is not empty.\n"); // 输出堆不为空的信息
}
// 删除并输出堆顶元素
int max = extractMax(heap); // 删除并返回最大元素
printf("Extracted max element: %d\n", max); // 打印删除的最大元素
// 再次打印输出当前堆的内容
printHeap(heap); // 打印当前堆的元素
destroyMaxHeap(heap); // 释放堆的内存
return 0; // 返回0表示程序正常结束
}