当前位置:   article > 正文

堆的基本操作(c语言实现)_c语言堆的基本操作

c语言堆的基本操作

 1.堆的基本操作

1.1定义堆

  1. typedef int HPDataType;//堆中存储数据的类型
  2. typedef struct Heap
  3. {
  4. HPDataType* a;//用于存储数据的数组
  5. int size;//记录堆中已有元素个数
  6. int capacity;//记录堆的容量
  7. }HP;

1.2初始化堆

然后我们需要一个初始化函数,对刚创建的堆进行初始化,注意在初始化期间要将传入数据建堆。

  1. //初始化堆
  2. void HeapInit(HP* php, HPDataType* a, int n)
  3. {
  4. assert(php);
  5. HPDataType* tmp = (HPDataType*)malloc(sizeof(HPDataType)*n);//申请一个堆结构
  6. if (tmp == NULL)
  7. {
  8. printf("malloc fail\n");
  9. exit(-1);
  10. }
  11. php->a = tmp;
  12. memcpy(php->a, a, sizeof(HPDataType)*n);//拷贝数据到堆中
  13. php->size = n;
  14. php->capacity = n;
  15. int i = 0;
  16. //建堆
  17. for (i = (php->size - 1 - 1) / 2; i >= 0; i--)
  18. {
  19. AdjustDown(php->a, php->size, i);
  20. }
  21. }

1.3 销毁堆

 为了避免内存泄漏,使用完动态开辟的内存空间后都要及时释放该空间,所以,一个用于释放内存空间的函数是必不可少的。

  1. //销毁堆
  2. void HeapDestroy(HP* php)
  3. {
  4. assert(php);
  5. free(php->a);//释放动态开辟的数组
  6. php->a = NULL;//及时置空
  7. php->size = 0;//元素个数置0
  8. php->capacity = 0;//容量置0
  9. }

1.4打印堆

 打印堆中的数据,这里用的打印格式是按照堆的物理结构进行打印,即打印为一排连续的数字。

  1. //打印堆
  2. void HeapPrint(HP* php)
  3. {
  4. assert(php);
  5. //按照物理结构进行打印
  6. int i = 0;
  7. for (i = 0; i < php->size; i++)
  8. {
  9. printf("%d ", php->a[i]);
  10. }
  11. printf("\n");
  12. }

1.5堆的插入

数据插入时是插入到数组的末尾,即树形结构的最后一层的最后一个结点,所以插入数据后我们需要运用堆的向上调整算法对堆进行调整,使其在插入数据后仍然保持堆的结构。

  1. void HeapPush(HP* php, HPDataType x)
  2. {
  3. assert(php);
  4. if (php->size == php->capacity)
  5. {
  6. HPDataType* tmp = (HPDataType*)realloc(php->a,
  7. sizeof(HPDataType) * php->capacity*2);
  8. if (tmp == NULL)
  9. {
  10. perror("realloc fail");
  11. return;
  12. }
  13. php->a = tmp;
  14. php->capacity *= 2;
  15. }
  16. php->a[php->size] = x;
  17. php->size++;
  18. AdjustUp(php->a, php->size - 1);
  19. }

 这个插入的效果完全取决于AdjustUp函数是给大堆设计的还是小堆!!

1.6堆的删除

堆的删除操作通常指的是从堆中移除最大值或最小值的操作。

在最大堆中,根节点是最大的元素,而在最小堆中,根节点是最小的元素。

以下是堆的删除操作的基本思路:

  1. 首先,将堆顶元素(即根节点)与最后一个元素交换位置,即将最大值或最小值移动到数组的末尾。
  2.  然后,将堆的大小减1,即删除了原来堆顶的元素。
  3. 最后,对新的堆顶元素进行向下调整,以保持堆的性质。在最大堆中,需要将新堆顶元素与其子节点中的较大者交换,直到满足最大堆的性质;在最小堆中,需要将新堆顶元素与其子节点中的较小者交换,直到满足最小堆的性质。

通过以上步骤,可以实现堆的删除操作,并保持堆的性质不变。

  1. //堆的删除
  2. void HeapPop(HP* php)
  3. {
  4. assert(php);
  5. assert(!HeapEmpty(php));
  6. Swap(&php->a[0], &php->a[php->size - 1]);//交换堆顶和最后一个结点的位置
  7. php->size--;//删除最后一个结点(也就是删除原来堆顶的元素)
  8. AdjustDown(php->a, php->size, 0);//向下调整
  9. }

这段代码是堆的删除操作,基本思路如下:

1. 首先,通过断言(assert)确保传入的堆指针(php)不为空,并且堆不为空。
2. 然后,将堆顶元素(索引为0的元素)与最后一个元素进行交换,即将堆顶元素移动到数组的末尾。
3. 接着,将堆的大小减1,即删除了原来堆顶的元素。
4. 最后,调用AdjustDown函数对新的堆顶元素进行向下调整,以保持堆的性质。

1.7.获取堆的数据个数

获取堆的数据个数,即返回堆结构体中的size变量。

  1. //获取堆中数据个数
  2. int HeapSize(HP* php)
  3. {
  4. assert(php);
  5. return php->size;//返回堆中数据个数
  6. }

1.8堆的判空

堆的判空,即判断堆结构体中的size变量是否为0。

  1. //堆的判空
  2. bool HeapEmpty(HP* php)
  3. {
  4. assert(php);
  5. return php->size == 0;//判断堆中数据是否为0
  6. }

2.完整操作加测试代码

  1. #include<stdio.h>
  2. #include<assert.h>
  3. #include<stdlib.h>
  4. #include<stdbool.h>
  5. #include<time.h>
  6. typedef int HPDataType;
  7. typedef struct Heap
  8. {
  9. HPDataType* a;
  10. int size;
  11. int capacity;
  12. }HP;
  13. void Swap(HPDataType* p1, HPDataType* p2)
  14. {
  15. HPDataType x = *p1;
  16. *p1 = *p2;
  17. *p2 = x;
  18. }
  19. //堆的向下调整(小堆)—— 左右子树都是小堆
  20. void AdjustDown(HPDataType* a, int n, int parent)
  21. {
  22. int child = parent * 2 + 1;
  23. while (child < n)
  24. {
  25. // 选出左右孩子中大的那一个
  26. if (child + 1 < n && a[child + 1] < a[child])
  27. {
  28. ++child;
  29. }
  30. if (a[child] < a[parent])
  31. {
  32. Swap(&a[child], &a[parent]);
  33. parent = child;
  34. child = parent * 2 + 1;
  35. }
  36. else
  37. {
  38. break;
  39. }
  40. }
  41. }
  42. //初始化堆
  43. void HeapInit(HP* php, HPDataType* a, int n)
  44. {
  45. assert(php);
  46. HPDataType* tmp = (HPDataType*)malloc(sizeof(HPDataType) * n);//申请一个堆结构
  47. if (tmp == NULL)
  48. {
  49. printf("malloc fail\n");
  50. exit(-1);
  51. }
  52. php->a = tmp;
  53. memcpy(php->a, a, sizeof(HPDataType) * n);//拷贝数据到堆中
  54. php->size = n;
  55. php->capacity = n;
  56. int i = 0;
  57. //建堆
  58. for (i = (php->size - 1 - 1) / 2; i >= 0; i--)
  59. {
  60. AdjustDown(php->a, php->size, i);
  61. }
  62. }
  63. bool HeapEmpty(HP* php)
  64. {
  65. assert(php);
  66. return php->size == 0;
  67. }
  68. void HeapDestroy(HP* php)
  69. {
  70. assert(php);
  71. free(php->a);
  72. php->a = NULL;
  73. php->capacity = php->size = 0;
  74. }
  75. //堆的向上调整(小堆)
  76. void AdjustUp(HPDataType* a, int child)
  77. {
  78. int parent = (child - 1) / 2;
  79. while (child > 0)//调整到根结点的位置截止
  80. {
  81. if (a[child] < a[parent])//孩子结点的值小于父结点的值
  82. {
  83. //将父结点与孩子结点交换
  84. Swap(&a[child], &a[parent]);
  85. //继续向上进行调整
  86. child = parent;
  87. parent = (child - 1) / 2;
  88. }
  89. else//已成堆
  90. {
  91. break;
  92. }
  93. }
  94. }
  95. void HeapPush(HP* php, HPDataType x)
  96. {
  97. assert(php);
  98. if (php->size == php->capacity)
  99. {
  100. HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * php->capacity * 2);
  101. if (tmp == NULL)
  102. {
  103. perror("realloc fail");
  104. return;
  105. }
  106. php->a = tmp;
  107. php->capacity *= 2;
  108. }
  109. php->a[php->size] = x;
  110. php->size++;
  111. AdjustUp(php->a, php->size - 1);
  112. }
  113. //打印堆
  114. void HeapPrint(HP* php)
  115. {
  116. assert(php);
  117. //按照物理结构进行打印
  118. int i = 0;
  119. for (i = 0; i < php->size; i++)
  120. {
  121. printf("%d ", php->a[i]);
  122. }
  123. printf("\n");
  124. }
  125. void HeapPop(HP* php)
  126. {
  127. assert(php);
  128. assert(!HeapEmpty(php));
  129. // 删除数据
  130. Swap(&php->a[0], &php->a[php->size - 1]);
  131. php->size--;
  132. AdjustDown(php->a, php->size, 0);
  133. }
  134. HPDataType HeapTop(HP* php)
  135. {
  136. assert(php);
  137. return php->a[0];
  138. }
  139. int HeapSize(HP* php)
  140. {
  141. assert(php);
  142. return php->size;
  143. }
  144. int main()
  145. {
  146. HP hp;
  147. int a[] = { 4,18,42,12,21,3,5,5,88,5,5,15,5,45,5 };
  148. int size = sizeof(a) / sizeof(a[0]);
  149. HeapInit(&hp,a,size);
  150. HeapPrint(&hp);
  151. HeapPop(&hp);
  152. HeapPrint(&hp);
  153. HeapPush(&hp, 4);
  154. HeapPrint(&hp);
  155. return 0;
  156. }

我们可以来验证一下是不是堆

  1. 堆的向上调整和向下调整的代码一定要是匹配的,小堆的只能和小堆匹配使用,大堆的只能和大堆匹配使用,要不然就会让你十分抓马 ,我就是因为错误匹配使用就导致了痛苦了两个晚上……
  2. 还有就是大家一定要去画图去验证一下这个是不是堆,不要用眼睛看
  3. 其次就是一定要建好堆后再使用堆的向上调整和向下调整

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

闽ICP备14008679号