当前位置:   article > 正文

数据结构的堆(c语言版)

数据结构的堆(c语言版)

一.堆的概念

1.堆的基本概念

在计算机科学中,堆是一种特殊的数据结构,通常用于实现优先队列和动态分配内存。

2.堆的特征

堆是一个完全二叉树,它具有以下两个主要特性:

  1. 堆序性:对于最大堆,在堆中的任意节点i,其父节点的值大于等于节点i的值;对于最小堆,在堆中的任意节点i,其父节点的值小于等于节点i的值。这意味着在最大堆中,根节点是堆中最大的元素;在最小堆中,根节点是堆中最小的元素。

  2. 完全二叉树性质:除了最底层外,堆的其他层都是满的,并且最底层的节点集中在左侧。

3.堆的性质

根据堆序性质,我们可以高效地找到堆中的最大(最小)元素。这使得堆非常适用于解决一些需要高效获取最大(最小)元素的问题,例如优先队列和排序算法(如堆排序)。

堆可以用数组来实现,其中父节点和子节点之间的关系可以通过索引计算得出。通常,堆的插入和删除操作会触发堆的调整,以维持堆序性质。

需要注意的是,堆和操作系统中的堆内存分配是不同的概念。在操作系统中,堆内存指的是动态分配的内存区域,而在数据结构中,堆是一种数据结构。

4.堆的优缺点

优点:

  1. 高效的插入和删除操作:在堆中,插入和删除元素的时间复杂度为O(log n),其中n是堆中元素的个数。这是由于堆的调整过程只需要对树的高度进行操作,堆的高度通常比较小。

  2. 快速获取最大(最小)元素:在最大堆中,根节点是堆中的最大元素;在最小堆中,根节点是堆中的最小元素。因此,可以在O(1)的时间复杂度内获取最大(最小)元素。

  3. 实现优先队列:堆常用于实现优先队列,其中元素按照优先级进行排序。优先队列可以在O(1)的时间复杂度内获取最高优先级的元素,并且在O(log n)的时间复杂度内插入和删除元素。

缺点:

  1. 不支持快速查找:堆并不提供快速查找指定元素的功能。如果需要在堆中进行查找操作,时间复杂度为O(n),需要遍历整个堆。

  2. 内存空间的浪费:堆使用数组来存储元素,如果事先不知道元素的个数,需要预分配一个较大的数组空间。这可能会导致内存空间的浪费。

  3. 不稳定性:堆排序算法是一种不稳定的排序算法。在排序过程中,相等元素的相对顺序可能会改变。

二.堆的功能

  1. 插入元素:向堆中插入一个新元素。插入操作会根据堆的特性进行调整,以保持堆的性质。

  2. 删除最大(最小)元素:从堆中删除并返回最大(最小)元素。删除操作会将堆的最后一个元素移到堆顶,并根据堆的特性进行调整,以保持堆的性质。

  3. 获取最大(最小)元素:返回堆中的最大(最小)元素,而不删除它。获取操作只是简单地返回堆的根节点的值。

  4. 堆排序:使用堆进行排序。堆排序是一种基于堆的排序算法,它利用堆的性质进行排序操作。

  5. 构建堆:将一个无序的数组转换为一个堆。构建堆的过程会进行堆调整,以满足堆的性质。

  6. 堆化:对一个已有的堆进行调整,以满足堆的性质。堆化可以通过自上而下或自下而上的方式进行。

  7. 堆的合并:将两个堆合并为一个堆。堆的合并操作通常用于合并多个优先队列。

  8. 查找元素:在堆中查找指定元素。由于堆并不提供快速查找功能,查找操作需要遍历整个堆,时间复杂度为O(n)。

三.堆的代码实现

1.堆的定义

创建一个结构体,其中成员如下:

  • array:一个指向整型数组的指针,用于存储堆中的元素。
  • capacity:一个整数,表示堆的容量,即 array 数组的最大长度。
  • size:一个整数,表示当前堆中的元素个数,即 array 数组中实际存储的元素数量。
  1. typedef struct {
  2. int* array; // 存储堆元素的数组
  3. int capacity; // 堆的容量
  4. int size; // 堆中当前元素的个数
  5. } Heap;

2.创建堆

创建堆。该函数接受一个整数参数 capacity,表示堆的容量。它会分配堆所需的内存,并返回指向堆结构的指针。

  1. // 创建堆
  2. Heap* createHeap(int capacity) {
  3. Heap* heap = (Heap*)malloc(sizeof(Heap));
  4. heap->array = (int*)malloc(sizeof(int) * capacity);
  5. heap->capacity = capacity;
  6. heap->size = 0;
  7. return heap;
  8. }

3.交换两个数值

交换两个元素的值。该函数接受两个整型指针作为参数,通过引用交换指针所指向的两个整数的值。

  1. // 交换两个元素
  2. void swap(int* a, int* b) {
  3. int temp = *a;
  4. *a = *b;
  5. *b = temp;
  6. }

4.入堆

向堆中插入元素。该函数接受一个指向堆结构的指针 heap 和要插入的整数值 value。它将元素插入到堆的最后位置,并通过自上而下的调整操作,保持堆的性质。

  1. // 向堆中插入元素
  2. void insert(Heap* heap, int value) {
  3. if (heap->size == heap->capacity) {
  4. printf("堆已满,无法插入新元素。\n");
  5. return;
  6. }
  7. // 将新元素插入到堆的最后位置
  8. heap->array[heap->size] = value;
  9. int currentIndex = heap->size;
  10. int parentIndex = (currentIndex - 1) / 2;
  11. // 自下而上调整堆结构
  12. while (currentIndex > 0 && heap->array[currentIndex] > heap->array[parentIndex]) {
  13. swap(&heap->array[currentIndex], &heap->array[parentIndex]);
  14. currentIndex = parentIndex;
  15. parentIndex = (currentIndex - 1) / 2;
  16. }
  17. heap->size++;
  18. }

5.出堆

从堆中删除并返回最大元素。该函数接受一个指向堆结构的指针 heap。它将堆顶元素(最大元素)删除,并将最后一个元素移到堆顶,然后通过自上而下的调整操作,保持堆的性质。

  1. // 从堆中删除并返回最大元素
  2. int deleteMax(Heap* heap) {
  3. if (heap->size == 0) {
  4. printf("堆为空,无法删除元素。\n");
  5. return -1;
  6. }
  7. int maxValue = heap->array[0];
  8. // 将最后一个元素移到堆顶
  9. heap->array[0] = heap->array[heap->size - 1];
  10. heap->size--;
  11. int currentIndex = 0;
  12. int leftChildIndex = 2 * currentIndex + 1;
  13. int rightChildIndex = 2 * currentIndex + 2;
  14. // 自上而下调整堆结构
  15. while (1) {
  16. int maxIndex = currentIndex;
  17. // 与左子节点比较
  18. if (leftChildIndex < heap->size && heap->array[leftChildIndex] > heap->array[maxIndex]) {
  19. maxIndex = leftChildIndex;
  20. }
  21. // 与右子节点比较
  22. if (rightChildIndex < heap->size && heap->array[rightChildIndex] > heap->array[maxIndex]) {
  23. maxIndex = rightChildIndex;
  24. }
  25. // 如果当前节点已经是最大值,则堆已调整完毕
  26. if (maxIndex == currentIndex) {
  27. break;
  28. }
  29. // 否则,交换当前节点与最大子节点的位置
  30. swap(&heap->array[currentIndex], &heap->array[maxIndex]);
  31. currentIndex = maxIndex;
  32. leftChildIndex = 2 * currentIndex + 1;
  33. rightChildIndex = 2 * currentIndex + 2;
  34. }
  35. return maxValue;
  36. }

6.打印堆

打印堆元素。该函数接受一个指向堆结构的指针 heap。它会遍历堆中的元素,并将它们打印出来。

  1. // 打印堆元素
  2. void printHeap(Heap* heap) {
  3. printf("堆元素:");
  4. for (int i = 0; i < heap->size; i++) {
  5. printf("%d ", heap->array[i]);
  6. }
  7. printf("\n");
  8. }

7.销毁堆

释放堆内存。该函数接受一个指向堆结构的指针 heap。它会释放堆所占用的内存,防止内存泄漏。

  1. // 释放堆内存
  2. void destroyHeap(Heap* heap) {
  3. free(heap->array);
  4. free(heap);
  5. }

四.堆的源码呈现

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. // 定义堆结构
  4. typedef struct {
  5. int* array; // 存储堆元素的数组
  6. int capacity; // 堆的容量
  7. int size; // 堆中当前元素的个数
  8. } Heap;
  9. // 创建堆
  10. Heap* createHeap(int capacity) {
  11. Heap* heap = (Heap*)malloc(sizeof(Heap));
  12. heap->array = (int*)malloc(sizeof(int) * capacity);
  13. heap->capacity = capacity;
  14. heap->size = 0;
  15. return heap;
  16. }
  17. // 交换两个元素
  18. void swap(int* a, int* b) {
  19. int temp = *a;
  20. *a = *b;
  21. *b = temp;
  22. }
  23. // 向堆中插入元素
  24. void insert(Heap* heap, int value) {
  25. if (heap->size == heap->capacity) {
  26. printf("堆已满,无法插入新元素。\n");
  27. return;
  28. }
  29. // 将新元素插入到堆的最后位置
  30. heap->array[heap->size] = value;
  31. int currentIndex = heap->size;
  32. int parentIndex = (currentIndex - 1) / 2;
  33. // 自下而上调整堆结构
  34. while (currentIndex > 0 && heap->array[currentIndex] > heap->array[parentIndex]) {
  35. swap(&heap->array[currentIndex], &heap->array[parentIndex]);
  36. currentIndex = parentIndex;
  37. parentIndex = (currentIndex - 1) / 2;
  38. }
  39. heap->size++;
  40. }
  41. // 从堆中删除并返回最大元素
  42. int deleteMax(Heap* heap) {
  43. if (heap->size == 0) {
  44. printf("堆为空,无法删除元素。\n");
  45. return -1;
  46. }
  47. int maxValue = heap->array[0];
  48. // 将最后一个元素移到堆顶
  49. heap->array[0] = heap->array[heap->size - 1];
  50. heap->size--;
  51. int currentIndex = 0;
  52. int leftChildIndex = 2 * currentIndex + 1;
  53. int rightChildIndex = 2 * currentIndex + 2;
  54. // 自上而下调整堆结构
  55. while (1) {
  56. int maxIndex = currentIndex;
  57. // 与左子节点比较
  58. if (leftChildIndex < heap->size && heap->array[leftChildIndex] > heap->array[maxIndex]) {
  59. maxIndex = leftChildIndex;
  60. }
  61. // 与右子节点比较
  62. if (rightChildIndex < heap->size && heap->array[rightChildIndex] > heap->array[maxIndex]) {
  63. maxIndex = rightChildIndex;
  64. }
  65. // 如果当前节点已经是最大值,则堆已调整完毕
  66. if (maxIndex == currentIndex) {
  67. break;
  68. }
  69. // 否则,交换当前节点与最大子节点的位置
  70. swap(&heap->array[currentIndex], &heap->array[maxIndex]);
  71. currentIndex = maxIndex;
  72. leftChildIndex = 2 * currentIndex + 1;
  73. rightChildIndex = 2 * currentIndex + 2;
  74. }
  75. return maxValue;
  76. }
  77. // 打印堆元素
  78. void printHeap(Heap* heap) {
  79. printf("堆元素:");
  80. for (int i = 0; i < heap->size; i++) {
  81. printf("%d ", heap->array[i]);
  82. }
  83. printf("\n");
  84. }
  85. // 释放堆内存
  86. void destroyHeap(Heap* heap) {
  87. free(heap->array);
  88. free(heap);
  89. }
  90. int main() {
  91. Heap* heap = createHeap(10);
  92. insert(heap, 5);
  93. insert(heap, 8);
  94. insert(heap, 2);
  95. insert(heap, 10);
  96. insert(heap, 3);
  97. printHeap(heap);
  98. int max = deleteMax(heap);
  99. printf("删除的最大元素:%d\n", max);
  100. printHeap(heap);
  101. destroyHeap(heap);
  102. return 0;
  103. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/573958
推荐阅读
相关标签
  

闽ICP备14008679号