C语言-堆(heap)的详解与实现

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表示程序正常结束
}

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值