当前位置:   article > 正文

堆(数据结构)

堆(数据结构)

目录

1.堆的定义:

1.堆是完全二叉树;

2.堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。

2.堆的代码实现: (小堆)

初始化(HeapInit):

插入(HeapPush):

删除堆顶元素(HeapPop):

查看堆顶元素(HeapPeek):

检查堆满(HeapFull)和堆空(HeapEmpty):

销毁堆(HeapDestroy):

堆化(Heapify):

上滤(adjustup)和下滤(adjustdown):

3.完整代码: 


1.堆的定义:

只要满足以下两个条件,就是堆(Heap)

1.堆是完全二叉树;

若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

2.堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。

小堆:任何一个父亲<=孩子

大堆:任何一个父亲>=孩子

2.堆的代码实现: (小堆)

存储结构:

  1. typedef int HeapDataType;
  2. typedef struct Heap {
  3. HeapDataType* hp;
  4. int size;
  5. int capacity;
  6. }Heap;
  1. 初始化(HeapInit)
    • 功能:为堆分配内存空间,并设置初始容量为n
    • 细节:使用malloc为堆的数据元素分配内存,并设置堆的大小为0,容量为n
      1. void HeapInit(Heap*heap,int n) {
      2. assert(heap);
      3. HeapDataType* hp = (HeapDataType*)malloc(n * sizeof(HeapDataType));
      4. if (hp == NULL) {
      5. perror("HeapInit:malloc");
      6. exit(1);
      7. }
      8. heap->hp = hp;
      9. heap->capacity = n;
      10. heap->size = 0;
      11. }

  2. 插入(HeapPush)
    • 功能:向堆中插入一个元素
    • 细节:首先检查堆是否已满,如果已满则尝试扩大堆的容量。然后将新元素添加到堆的末尾,并通过adjustup函数调整堆的结构以保持小堆的性质(即父节点值不大于孩子节点值)。
      1. void HeapPush(Heap* heap,HeapDataType x) {
      2. assert(heap);
      3. if (HeapFull(heap)) {
      4. int new = heap->capacity == 0 ? 4 : 2 * heap->capacity;
      5. HeapDataType* tmp = (HeapDataType*)realloc(heap->hp, new * sizeof(HeapDataType));
      6. if (tmp == NULL) {
      7. perror("HeapPush:realloc");
      8. exit(1);
      9. }
      10. heap->hp = tmp;
      11. heap->capacity = new;
      12. }
      13. heap->hp[heap->size] = x;
      14. adjustup(heap->hp, heap->size);
      15. heap->size++;
      16. }

  3. 删除堆顶元素(HeapPop)
    • 功能:删除堆顶元素(即最小元素),并重新调整堆的结构
    • 细节:首先检查堆是否为空。然后将堆的最后一个元素移到堆顶,并通过adjustdown函数重新调整堆以保持小堆性质。堆的大小减1。
      1. void HeapPop(Heap* heap) {
      2. assert(heap);
      3. if (HeapEmpty(heap)) {
      4. perror("HeapPop:NULL");
      5. exit(1);
      6. }
      7. HeapDataType x = heap->hp[0];
      8. heap->hp[0] = heap->hp[heap->size - 1];
      9. heap->hp[heap->size - 1] = x;
      10. heap->size--;
      11. adjustdown(heap->hp, 0, heap->size);
      12. }

  4. 查看堆顶元素(HeapPeek)
    • 功能:返回堆顶元素的值,但不删除它
    • 细节:直接返回堆顶元素的值。这通常用于查看当前最小元素的值,而不改变堆的结构。
      1. HeapDataType HeapPeek(Heap*heap) {
      2. assert(heap);
      3. if (HeapEmpty(heap)) {
      4. perror("HeapPeek:NULL");
      5. exit(1);
      6. }
      7. return heap->hp[0];
      8. }

  5. 检查堆满(HeapFull)和堆空(HeapEmpty)
    • 功能:检查堆是否已满或是否为空
    • 细节:HeapFull检查堆的大小是否等于其容量,而HeapEmpty检查堆的大小是否为0。
      1. bool HeapFull(Heap*heap) {
      2. return heap->capacity == heap->size;
      3. }
      1. bool HeapEmpty(Heap* heap) {
      2. return heap->size == 0;
      3. }

  6. 销毁堆(HeapDestroy)
    • 功能:释放堆所占用的内存空间
    • 细节:使用free函数释放堆的数据元素所占用的内存,并将堆的指针、容量和大小都重置为0。
      1. void HeapDestory(Heap*heap) {
      2. assert(heap&&heap->hp);
      3. free(heap->hp);
      4. heap->hp = NULL;
      5. heap->capacity = 0;
      6. heap->size = 0;
      7. }

  7. 堆化(Heapify)
    • 功能:将一个数组重新调整为小堆结构
    • 细节:通常用于在堆构建完成后或在执行某些操作(如删除元素)后重新调整堆的结构。从最后一个非叶子节点开始,自底向上调整每个节点,以保持小堆的性质。
      1. void Heapify(HeapDataType*a,int n) {
      2. assert(a);
      3. int i = (n - 1 - 1) / 2 ;
      4. for (i; i >= 0; i--) {
      5. adjustdown(a, i, n);
      6. }
      7. }

  8. 上滤(adjustup)和下滤(adjustdown)
    • 功能:这两个函数用于在插入或删除元素后调整堆的结构。
    • 细节:adjustup用于在插入新元素后,从插入位置开始向上调整堆结构;adjustdown用于在删除堆顶元素后,从堆顶开始向下调整堆结构。这两个函数都通过比较节点与其子节点的值,并交换它们(如果需要)来保持小堆的性质。
      1. void adjustup(HeapDataType*hp,int i) {
      2. assert(hp);
      3. int j = (i - 1) / 2;
      4. while (j>=0) {
      5. if (hp[i] < hp[j]) {
      6. HeapDataType x = hp[i];
      7. hp[i] = hp[j];
      8. hp[j] = x;
      9. i = j;
      10. j = (i - 1) / 2;
      11. }
      12. else {
      13. break;
      14. }
      15. }
      16. }
      1. void adjustdown(HeapDataType* hp, int i, int n) {
      2. assert(hp&&i<n);
      3. int j = 2 * i + 1;
      4. if (hp[j] > hp[j + 1]&&j<n-1) {
      5. j++;
      6. }
      7. if (hp[j] < hp[i]&&j<n) {
      8. HeapDataType x = hp[i];
      9. hp[i] = hp[j];
      10. hp[j] = x;
      11. adjustdown(hp, j, n);
      12. }
      13. }

3.完整代码: 

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<assert.h>
  4. #include<stdbool.h>
  5. typedef int HeapDataType;
  6. typedef struct Heap {
  7. HeapDataType* hp;
  8. int size;
  9. int capacity;
  10. }Heap;
  11. //小堆
  12. void adjustup(HeapDataType*hp,int i) {
  13. assert(hp);
  14. int j = (i - 1) / 2;
  15. while (j>=0) {
  16. if (hp[i] < hp[j]) {
  17. HeapDataType x = hp[i];
  18. hp[i] = hp[j];
  19. hp[j] = x;
  20. i = j;
  21. j = (i - 1) / 2;
  22. }
  23. else {
  24. break;
  25. }
  26. }
  27. }
  28. void adjustdown(HeapDataType* hp, int i, int n) {
  29. assert(hp&&i<n);
  30. int j = 2 * i + 1;
  31. if (hp[j] > hp[j + 1]&&j<n-1) {
  32. j++;
  33. }
  34. if (hp[j] < hp[i]&&j<n) {
  35. HeapDataType x = hp[i];
  36. hp[i] = hp[j];
  37. hp[j] = x;
  38. adjustdown(hp, j, n);
  39. }
  40. }
  41. void HeapInit(Heap*heap,int n) {
  42. assert(heap);
  43. HeapDataType* hp = (HeapDataType*)malloc(n * sizeof(HeapDataType));
  44. if (hp == NULL) {
  45. perror("HeapInit:malloc");
  46. exit(1);
  47. }
  48. heap->hp = hp;
  49. heap->capacity = n;
  50. heap->size = 0;
  51. }
  52. void Heapify(HeapDataType*a,int n) {
  53. assert(a);
  54. int i = (n - 1 - 1) / 2 ;
  55. for (i; i >= 0; i--) {
  56. adjustdown(a, i, n);
  57. }
  58. }
  59. void HeapDestory(Heap*heap) {
  60. assert(heap&&heap->hp);
  61. free(heap->hp);
  62. heap->hp = NULL;
  63. heap->capacity = 0;
  64. heap->size = 0;
  65. }
  66. bool HeapFull(Heap*heap) {
  67. return heap->capacity == heap->size;
  68. }
  69. bool HeapEmpty(Heap* heap) {
  70. return heap->size == 0;
  71. }
  72. void HeapPush(Heap* heap,HeapDataType x) {
  73. assert(heap);
  74. if (HeapFull(heap)) {
  75. int new = heap->capacity == 0 ? 4 : 2 * heap->capacity;
  76. HeapDataType* tmp = (HeapDataType*)realloc(heap->hp, new * sizeof(HeapDataType));
  77. if (tmp == NULL) {
  78. perror("HeapPush:realloc");
  79. exit(1);
  80. }
  81. heap->hp = tmp;
  82. heap->capacity = new;
  83. }
  84. heap->hp[heap->size] = x;
  85. adjustup(heap->hp, heap->size);
  86. heap->size++;
  87. }
  88. void HeapPop(Heap* heap) {
  89. assert(heap);
  90. if (HeapEmpty(heap)) {
  91. perror("HeapPop:NULL");
  92. exit(1);
  93. }
  94. HeapDataType x = heap->hp[0];
  95. heap->hp[0] = heap->hp[heap->size - 1];
  96. heap->hp[heap->size - 1] = x;
  97. heap->size--;
  98. adjustdown(heap->hp, 0, heap->size);
  99. }
  100. HeapDataType HeapPeek(Heap*heap) {
  101. assert(heap);
  102. if (HeapEmpty(heap)) {
  103. perror("HeapPeek:NULL");
  104. exit(1);
  105. }
  106. return heap->hp[0];
  107. }
  108. int main()
  109. {
  110. Heap* heap = (Heap*)malloc(sizeof(Heap));
  111. HeapInit(heap, 5);
  112. HeapPush(heap, 4);
  113. HeapPush(heap, 2);
  114. HeapPush(heap, 15);
  115. HeapPush(heap, 7);
  116. HeapPush(heap, 9);
  117. for (int i = 0; i < 5; i++) {
  118. printf("%d ", heap->hp[i]);
  119. }
  120. HeapDestory(heap);
  121. return 0;
  122. }

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

闽ICP备14008679号