当前位置:   article > 正文

数据结构---堆排序_堆排序从小到大排用什么堆

堆排序从小到大排用什么堆

1、叶子完全二叉树:节点必须按从左到右存放,少也要从右边节点开始少,不能从中间突然少一个节点

满二叉树:也是完全二叉树的特例

大顶堆:父节点的值大于孩子节点                               小顶堆:父节点的值小于孩子节点

                                                 

 叶子节点:

2、堆排序:默认从小到大排序,使用大顶堆

                    默认从大到小,使用小顶堆

(1)、先将数组中的数据想象成一个完全二叉树的结构 

 (2)将其调整为大顶堆,观察调整完毕的大顶堆,可得到根节点的值一定是所有值中最大值,现在已将找到了最大值,则可以将最大值与最后一个值的进行位置交换,最后一个位置记为最大值,相当于完成了一趟冒泡排序

        整规则:从最后一个非叶子节点开始调整(从右向左、从下到上),将其作为临时根节点去调整(非叶子节点一共有三个13 、12、21,最后一个非叶子节点是13)

先调整红色框,再橙色框,最后绿色框(依据从右向左、从下到上)

红色框调整:

步骤:(i)先将根节点的值取出来保存到tmp,

           (ii)需要找到当前空白节点的较大的孩子节点

           (iii)较大孩子节点和tmp比较,如果比tmp大,则将较大的孩子节点向上移动

           (iv)孩子节点移动后,不能直接将tmp插入倒原先较大孩子的位置上,因为它可能还有孩子节点的值比起大

           (v)那么tmp什么时候插入?

                    a:触底(较大的孩子节点没有孩子节点)

                    b:较大孩子节点的孩子节点值都小于tmp

(3)将最大值和最后一个节点的值进行交换,然后将尾节点剔除,不参与下一次排序

(4)重读(2)、(3),直到有序节点只剩一个,则结束。

        现在,如果继续调整为大顶堆,则不需要从内到外调整,只许将最大的那个框调整一次即可,因为只有一根节点为初始节点的框受到影响,可能不稳定,其他框不受影响。

 例如,一次调整之后如上图,只有绿色不稳定,其他框依旧保持大顶堆状态。

调整流程图: 

 

3、父节点位置为i,左右孩子节点的位置下标为2i+1,2i+2

     子节点位置为i,父节点的位置下标为   (i-1)/2  取整

堆排序代码:

  1. //一次调整函数时间复杂度O(log2 n),空间复杂度
  2. void HeapAdjust(int arr[],int start,int end)
  3. {
  4. //assert
  5. int tmp = arr[start];
  6. for (int i = start * 2 + 1; i <= end;i = start * 2+1)//start*2+1相当于start节点的左孩子
  7. {
  8. if (i<end && arr[i + 1]>arr[i])//i<end代表存在右孩子,且右孩子的值大于左孩子
  9. {
  10. i++;//此时i指向右孩子
  11. }
  12. //此时i指向较大的孩子
  13. if (arr[i] > tmp)
  14. {
  15. arr[start] = arr[i];
  16. start = i;//更改start的位置,i指向新的子孩子位置,体现在for循环语句3
  17. }
  18. else
  19. {
  20. break;//退出for循环,触发情况2
  21. }
  22. }
  23. arr[start] = tmp;
  24. }
  25. //堆排序,时间复杂度O(n*log2 n),空间复杂度O(1),不稳定
  26. void HeapSort(int* arr, int len)
  27. {
  28. //1、整体从最后一个非叶子节点由内到外调整
  29. //首先需要知道最后一个非叶子节点的下标,
  30. for (int i = (len - 1-1) / 2; i >= 0; i--)//因为最后一个非叶子结点是最后一个叶子结点的父节点,最后一个叶子节点的下标为len-1
  31. {
  32. HeapAdjust(arr, i,len-1);//调用一次调整函数,i为一次调整的父节点下标,这里第三个参数没有规律,则直接给最大值
  33. }
  34. //此时,已经调整为大顶堆
  35. //此时,当前根节点的值和当前最后一个节点的值进行交换,最后将当前尾节点剔除
  36. for (int i = 0; i < len - 1; i++)
  37. {
  38. int tmp = arr[0];
  39. arr[0] = arr[len - 1 - i];//当前根节点的值和当前最后一个节点的值进行交换
  40. arr[len - 1 - i] = tmp;
  41. HeapAdjust(arr, 0, (len - 1 - i) - 1);//此时只需要再次调用一次调整为大顶堆的一次函数.len-1-i是当前的尾节点,再给其-1,相当于提出当前最后一个尾节点
  42. }
  43. }
  44. void Show(int arr[], int len)
  45. {
  46. for (int i = 0; i < len; i++)
  47. {
  48. printf("%d ", arr[i]);
  49. }
  50. printf("\n");
  51. }
  52. int main()
  53. {
  54. int arr[] = { 12,2,39,88,4,6,25,232,62,221 };
  55. HeapSort(arr, sizeof(arr) / sizeof(arr[0]));
  56. Show(arr, sizeof(arr) / sizeof(arr[0]));
  57. return 0;
  58. }

结果:

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号