当前位置:   article > 正文

【数据结构初阶】二叉树顺序结构:堆的实现

【数据结构初阶】

前言

前边077带着大家学习了树与二叉树的相关概念,这篇文章我们来实现一个二叉树的顺序结构


二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结 构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

与前边的栈类似,数据结构中的堆与地址空间的堆是完全不同的,是两个学科中的名词。 


 

堆的概念及结构 

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。
数据结构堆的概念&&堆排序的思想以及算法过程详解(图文)_LifeGoesOn-CSDN博客_数据结构建堆过程

 

小堆,又叫小根堆,小顶堆,顾名思义就是这个堆的根节点数据是最小的,而且每一个父节点的数据都要小于子节点的数据,有一个不满足都不是小堆。
大堆就是根节点最大的堆,堆中每一个父节点的数据都是大于子结点的数据。

堆的实现

堆的接口实现

1.堆的结构

  1. typedef int hpDataType;
  2. typedef struct heap
  3. {
  4. hpDataType* a;
  5. int size;
  6. int capacity;
  7. }hp;
堆是顺序的二叉树,所以要定义一个顺序表,在物理上就是一个顺序表,在逻辑上确是一个二叉树,也就是堆。
2.初始化
  1. void hpInit(hp* ph)
  2. {
  3. assert(ph);
  4. ph->a = NULL;
  5. ph->capacity = ph->size = 0;
  6. }

3.销毁顺序表

  1. void hpDestory(hp* ph)
  2. {
  3. assert(ph);
  4. free(ph->a);
  5. ph->a = NULL;
  6. ph->capacity = ph->size = 0;
  7. }

4.向上调整

  1. void adjustUp(hpDataType* a, int child)
  2. {
  3. int parent = (child - 1) / 2;
  4. while (child > 0)
  5. {
  6. if (a[child] > a[parent])
  7. {
  8. int tmp = a[child];
  9. a[child] = a[parent];
  10. a[parent] = tmp;
  11. child = parent;
  12. parent = (child - 1) / 2;
  13. }
  14. else
  15. {
  16. break;
  17. }
  18. }
  19. }

使用向上调整算法可以随意插入数据,并且还不改变堆,还为一个小堆或者大堆,我这里实现的是一个大堆。

5.堆的插入
  1. void hpPush(hp* ph, hpDataType x)
  2. {
  3. assert(ph);
  4. if (ph->size == ph->capacity)
  5. {
  6. hpDataType newCapacity = ph->capacity == 0 ? 4 : ph->capacity * 2;
  7. hpDataType* tmp = (hpDataType*)realloc(ph->a, sizeof(hpDataType)*newCapacity);
  8. if (tmp == NULL)
  9. {
  10. perror("realloc fail/n");
  11. exit(-1);
  12. }
  13. ph->a = tmp;
  14. ph->capacity = newCapacity;
  15. }
  16. ph->a[ph->size] = x;
  17. ph->size++;
  18. adjustUp(ph->a, ph->size - 1);
  19. }

在堆中插入数据的前提是不改变堆的性质,使其还是一个堆,所以我们可以在最后一个位置处插入数据,再调用向上调整函数来实现插入,当然与顺序表相同的是,当容量不够时我们要进行扩容操作。

6.向下调整算法

  1. void adjustDown(hpDataType* a, int size, int parent)
  2. {
  3. int child = parent * 2 + 1;
  4. //调整到没有孩子结点
  5. while (child < size)
  6. {
  7. if (child + 1 < size && a[child + 1] < a[child])
  8. {
  9. child++;
  10. }
  11. if (a[child] < a[parent])
  12. {
  13. swap(&a[parent], & a[child]);
  14. parent = child;
  15. child = parent * 2 + 1;
  16. }
  17. else
  18. {
  19. break;
  20. }
  21. }
  22. }

我们使用向下调整函数也可以实现大堆和小堆,当某一节点不存在孩子结点时,向下调整结束,由于一个父节点存在左子树和右子树,所以我们在调整时,应该判断左右子树数据的大小并且判断右子树是否存在,来决定child的位置,再比较与父节点的位置来交换父节点与孩子结点。

7.堆的删除

  1. void hpPop(hp* ph)
  2. {
  3. assert(ph);
  4. assert(!hpEmpty(ph));
  5. swap(&ph->a[ph->size - 1], &ph->a[0]);
  6. ph->size--;
  7. adjustDown(ph->a, ph->size, 0);
  8. }

堆中数据的删除实际上指的是将堆顶数据进行删除,我们要进行的操作是将堆中最后一个数与堆顶元素互换,然后将堆的数据个数减一,这样就删除了堆顶元素,但是此时可能改变了堆的结构,我们再使用向下调整算法,调整根节点就能恢复了。

8.判空

  1. bool hpEmpty(hp* ph)
  2. {
  3. assert(ph);
  4. return ph->size == 0;
  5. }

9.取堆顶数据

  1. hpDataType hpTop(hp* ph)
  2. {
  3. assert(ph);
  4. assert(!hpEmpty(ph));
  5. return ph->a[0];
  6. }

10.打印堆中数据

  1. void hpPrint(hp* hp)
  2. {
  3. for (int i = 0; i < hp->size; ++i)
  4. {
  5. printf("%d ", hp->a[i]);
  6. }
  7. printf("\n");
  8. }

源码

heap.h

  1. #include<stdlib.h>
  2. #include<stdbool.h>
  3. #include<time.h>
  4. typedef int hpDataType;
  5. typedef struct heap
  6. {
  7. hpDataType* a;
  8. int size;
  9. int capacity;
  10. }hp;
  11. void adjustUp(hpDataType* a, int child);
  12. void adjustDown(hpDataType* a, int size, int child);
  13. void swap(int* px, int* py);
  14. void hpInit(hp* ph);
  15. void hpDestory(hp* ph);
  16. void hpPush(hp* ph, hpDataType x);
  17. void hpPop(hp* ph);
  18. bool hpEmpty(hp* ph);
  19. void hpPrint(hp* ph);
  20. hpDataType hpTop(hp* ph);

heap.c

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"heap.h"
  3. void swap(int* px, int* py)
  4. {
  5. int tmp = *px;
  6. *px = *py;
  7. *py = tmp;
  8. }
  9. void adjustUp(hpDataType* a, int child)
  10. {
  11. int parent = (child - 1) / 2;
  12. //调整到孩子结点就是根节点结束
  13. while (child > 0)
  14. {
  15. if (a[child] > a[parent])
  16. {
  17. int tmp = a[child];
  18. a[child] = a[parent];
  19. a[parent] = tmp;
  20. child = parent;
  21. parent = (child - 1) / 2;
  22. }
  23. else
  24. {
  25. break;
  26. }
  27. }
  28. }
  29. void adjustDown(hpDataType* a, int size, int parent)
  30. {
  31. int child = parent * 2 + 1;
  32. //调整到没有孩子结点
  33. while (child < size)
  34. {
  35. if (child + 1 < size && a[child + 1] < a[child])
  36. {
  37. child++;
  38. }
  39. if (a[child] < a[parent])
  40. {
  41. swap(&a[parent], & a[child]);
  42. parent = child;
  43. child = parent * 2 + 1;
  44. }
  45. else
  46. {
  47. break;
  48. }
  49. }
  50. }
  51. void hpInit(hp* ph)
  52. {
  53. assert(ph);
  54. ph->a = NULL;
  55. ph->capacity = ph->size = 0;
  56. }
  57. void hpDestory(hp* ph)
  58. {
  59. assert(ph);
  60. free(ph->a);
  61. ph->a = NULL;
  62. ph->capacity = ph->size = 0;
  63. }
  64. void hpPush(hp* ph, hpDataType x)
  65. {
  66. assert(ph);
  67. if (ph->size == ph->capacity)
  68. {
  69. hpDataType newCapacity = ph->capacity == 0 ? 4 : ph->capacity * 2;
  70. hpDataType* tmp = (hpDataType*)realloc(ph->a, sizeof(hpDataType)*newCapacity);
  71. if (tmp == NULL)
  72. {
  73. perror("realloc fail/n");
  74. exit(-1);
  75. }
  76. ph->a = tmp;
  77. ph->capacity = newCapacity;
  78. }
  79. ph->a[ph->size] = x;
  80. ph->size++;
  81. adjustUp(ph->a, ph->size - 1);
  82. }
  83. void hpPop(hp* ph)
  84. {
  85. assert(ph);
  86. assert(!hpEmpty(ph));
  87. swap(&ph->a[ph->size - 1], &ph->a[0]);
  88. ph->size--;
  89. adjustDown(ph->a, ph->size, 0);
  90. }
  91. bool hpEmpty(hp* ph)
  92. {
  93. assert(ph);
  94. return ph->size == 0;
  95. }
  96. void hpPrint(hp* hp)
  97. {
  98. for (int i = 0; i < hp->size; ++i)
  99. {
  100. printf("%d ", hp->a[i]);
  101. }
  102. printf("\n");
  103. }
  104. hpDataType hpTop(hp* ph)
  105. {
  106. assert(ph);
  107. assert(!hpEmpty(ph));
  108. return ph->a[0];
  109. }

test.c

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"heap.h"
  3. void test()
  4. {
  5. hp h;
  6. hpInit(&h);
  7. int a[] = { 70, 56, 30, 25, 15, 10, 1 };
  8. for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
  9. {
  10. hpPush(&h, a[i]);
  11. }
  12. hpPrint(&h);
  13. hpDestory(&h);
  14. }
  15. int main()
  16. {
  17. test();
  18. //testTopk();
  19. return;
  20. }

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

闽ICP备14008679号