当前位置:   article > 正文

排序算法--堆排序

排序算法--堆排序

堆排序的时间复杂度是O(N*logN),优于选择排序O(N^2)

一、堆

1.堆的概念:堆一般指的是二叉堆,顾名思义,二叉堆是完全二叉树或者近似完全二

2.堆的性质:①完全二叉树

                     ②每个节点的值都大于或等于其子节点的值,为最大堆;反之为最小堆。

3.堆的存储结构是数组,逻辑结构是二叉树

二、 堆排序(包括建堆和排序):

1.建堆的实现原理:

用到向下调整算法,比较两个孩子的大小,选出大的孩子,与父亲比较,如果孩子大于父亲,交换。然后把parent=child,child=parent*2+1;向下调整算法一共会调整h-1次,因此时间复杂度是O(logN)

从最后一个非叶子的节点开始用向下调整算法,实现建大堆。(建小堆就是> < 符号的改变)

2.向下调整算法的过程:

  1. void swap(int* a, int* b)//实现交换的函数
  2. {
  3. int tmp = *a;
  4. *a = *b;
  5. *b = tmp;
  6. }
  7. //前提下面都是大堆
  8. void AdjustDown(int* a, int n,int root)//向下调整算法
  9. {
  10. int parent = root;
  11. int child = parent * 2 + 1;//默认是左孩子,逻辑结构中二叉树的一个规律,左孩子=父亲*2+1
  12. while (child < n)
  13. {
  14. if (child+1<n && a[child] < a[child+1])//排大堆,如果右孩子更大,就让child是右孩子
  15. {
  16. child += 1;
  17. }
  18. if (a[child] > a[parent])//排大堆,如果孩子大于父亲,交换,并且依次向下调整
  19. {
  20. swap(&a[parent], &a[child]);
  21. parent = child;
  22. child = parent * 2 + 1;
  23. }
  24. else//已经是大堆了,退出while循环
  25. {
  26. break;
  27. }
  28. }

 3.建堆:

  1. //建堆:从最后一个非叶子节点开始调整,就可以达到下面都是大堆
  2. for (int i = (n - 1 - 1) / 2; i >= 0; i--)//n-1是最后一个数组下标,求父亲(下标-1)/2
  3. {
  4. AdjustDown(arr, n, i);
  5. }

4.建堆的时间复杂度是O(N)-->(粗略的了解原理,记住结论就行)

 5.排序:(用大堆)

用小堆的坏处:交换之后踢出第一个数,会导致堆的错位,要重新建堆,时间复杂度O(N^2)

排序的原理:

把第一个最大的数与最后一个数交换,然后把最后一个数踢出堆,继续向下调整算法,再交换次大的数。

  1. int end = n - 1;
  2. while (end > 0)
  3. {
  4. swap(&arr[0], &arr[end]);
  5. AdjustDown(arr, end, 0);//把交换之后的根,向下调整,调整h-1次,又变成大堆,再交换,可以得到次小的数
  6. end--;
  7. }

堆排序的所有代码:

  1. #include<stdio.h>
  2. void swap(int* a, int* b)
  3. {
  4. int tmp = *a;
  5. *a = *b;
  6. *b = tmp;
  7. }
  8. //前提下面都是大(小)堆
  9. void AdjustDown(int* a, int n,int root)
  10. {
  11. int parent = root;
  12. int child = parent * 2 + 1;//默认是左孩子
  13. while (child < n)
  14. {
  15. if (child+1<n && a[child] < a[child+1])//排大堆
  16. {
  17. child += 1;
  18. }
  19. if (a[child] > a[parent])//排大堆
  20. {
  21. swap(&a[parent], &a[child]);
  22. parent = child;
  23. child = parent * 2 + 1;
  24. }
  25. else
  26. {
  27. break;
  28. }
  29. }
  30. }
  31. void HeapSort(int* arr, int n)
  32. {
  33. for (int i = (n - 1 - 1) / 2; i >= 0; i--)//n-1是最后一个数组下标,求父亲(下标-1)/2
  34. {
  35. AdjustDown(arr, n, i);
  36. }
  37. int end = n - 1;
  38. while (end > 0)
  39. {
  40. swap(&arr[0], &arr[end]);
  41. AdjustDown(arr, end, 0);//把交换之后的根,向下调整,调整h-1次,又变成大堆,再交换,可以得到次小的数
  42. end--;
  43. }
  44. }
  45. int main()
  46. {
  47. int arr[] = { 10,1,5,3,6,8,7,4,9};
  48. int n = sizeof(arr) / sizeof(arr[0]);
  49. HeapSort(arr, n);
  50. for (int i = 0; i < n; i++)
  51. {
  52. printf("%d ", arr[i]);
  53. }
  54. return 0;
  55. }

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/163807
推荐阅读
相关标签
  

闽ICP备14008679号