当前位置:   article > 正文

【C语言】五分钟快速了解堆排序!_堆排序c语言

堆排序c语言

堆排序

一.前言

二.堆的建立

1.数组中父节点与子节点的关系

2.向下调整建堆法

①条件

②建堆思路

③实现代码

④建堆效果

三.堆的排序

①排序思路

②实现代码

③排序效果

四.时间复杂度

五.源码分享


一.前言

堆排序,顾名思义,对堆进行排序,那么问题来了,没有堆怎么排序呢?那就建堆好啦!所以,堆排序首先就得对排序目标建堆,然后再对建好的堆进行排序。本文将演示对数组的升序堆排序!

堆排序中升序要用到大堆根;而降序则要用到小堆根。

二.堆的建立

1.数组中父节点与子节点的关系

如果父节点的下标为n,那么子节点的下标就为2n+1、2n+2;

如果子节点(不论左孩子右孩子)的下标为n,那么父节点的下标就为(n-1)/2。

具体推导过程可以自己试着求一下哦~

2.向下调整建堆法

①条件

除调整数字外,该数字的所有子节点都为堆。

②建堆思路

在调整每个父节点之前,把子节点都建好堆。也就是从最后一个父节点开始,往前走一个一个地建堆。

③实现代码

  1. //两数交换
  2. void Swap(int* a, int* b)
  3. {
  4. int s = *a;
  5. *a = *b;
  6. *b = s;
  7. }
  8. //向下调整堆
  9. void AdjustDown(int* a, int size, int i)
  10. {
  11. int parent = i;
  12. int child = parent * 2 + 1;
  13. while (child < size)
  14. {
  15. // 升序,取两孩子中大的那个与父节点比较
  16. if (child + 1 < size && a[child + 1] > a[child])
  17. child++;
  18. // 升序,如果子节点比父节点大,则交换
  19. if (a[child] > a[parent])
  20. Swap(&a[child], &a[parent]);
  21. else
  22. break;
  23. // 子节点变为父节点,进行下一轮比较
  24. parent = child;
  25. child = parent * 2 + 1;
  26. }
  27. }
  28. //堆的创建
  29. void HeapCreate(int* a, int n)
  30. {
  31. assert(a);
  32. int child = n - 1; // 找到最后一个子节点
  33. int parent = (child - 1) / 2; // 找到最后一个父节点
  34. for (int i = parent; i >= 0; i--) // 从最后一个父节点开始到第一个父节点结束建堆
  35. {
  36. AdjustDown(a, n, i); // 向下调整堆
  37. }
  38. }

除了向下调整建堆法,还有一个向上调整的,不过其时间复杂度跟冒泡有一比,那就不多赘述啦!

④建堆效果

对调整后的数组画图检测一下:

三.堆的排序

①排序思路

已经知道最大数在堆首啦,而刚好要升序,那么,把堆首和堆尾交换一下不就好了嘛。

交换以后,将除最后一个元素的数组都视为堆,再对整个堆向下调整,便又获得一个新的大堆啦!

然后不断循环循环,每次堆首的最大值都往后放,直到遇到堆首便排序完毕了。

②实现代码

  1. //堆排序
  2. void HeapSort(int* a, int n)
  3. {
  4. //建堆
  5. HeapCreate(a, n);
  6. //排序堆
  7. for (int i = n; i > 0; i--)
  8. {
  9. Swap(&a[0], &a[i - 1]);
  10. AdjustDown(a, i - 1, 0);
  11. }
  12. }

③排序效果

 到这里堆排序便圆满结束啦!

四.时间复杂度

堆排序的时间复杂度为O(NlogN):

向下调整建堆的时间复杂度为O(N);

调整最大数并调整堆的时间复杂度为O(N^2)。

五.源码分享

  1. //两数交换
  2. void Swap(int* a, int* b)
  3. {
  4. int s = *a;
  5. *a = *b;
  6. *b = s;
  7. }
  8. //向下调整堆
  9. void AdjustDown(int* a, int size, int i)
  10. {
  11. int parent = i;
  12. int child = parent * 2 + 1;
  13. while (child < size)
  14. {
  15. // 升序,取两孩子中大的那个与父节点比较
  16. if (child + 1 < size && a[child + 1] > a[child])
  17. child++;
  18. // 升序,如果子节点比父节点大,则交换
  19. if (a[child] > a[parent])
  20. Swap(&a[child], &a[parent]);
  21. else
  22. break;
  23. // 子节点变为父节点,进行下一轮比较
  24. parent = child;
  25. child = parent * 2 + 1;
  26. }
  27. }
  28. //堆的创建
  29. void HeapCreate(int* a, int n)
  30. {
  31. assert(a);
  32. int child = n - 1; // 找到最后一个子节点
  33. int parent = (child - 1) / 2; // 找到最后一个父节点
  34. for (int i = parent; i >= 0; i--) // 从最后一个父节点开始到第一个父节点结束建堆
  35. {
  36. AdjustDown(a, n, i); // 向下调整堆
  37. }
  38. }
  39. //堆排序
  40. void HeapSort(int* a, int n)
  41. {
  42. //建堆
  43. HeapCreate(a, n);
  44. //排序堆
  45. for (int i = n; i > 0; i--)
  46. {
  47. Swap(&a[0], &a[i - 1]);
  48. AdjustDown(a, i - 1, 0);
  49. }
  50. }
  51. int main()
  52. {
  53. int a[] = { 10,8,9,3,5,4,6,2,1,7 };
  54. for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
  55. {
  56. printf("%d ", a[i]);
  57. }
  58. printf("\n");
  59. HeapSort(a, sizeof(a) / sizeof(a[0]));
  60. for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
  61. {
  62. printf("%d ", a[i]);
  63. }
  64. return 0;
  65. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/615363
推荐阅读
相关标签
  

闽ICP备14008679号