当前位置:   article > 正文

堆排序的详细讲解及实现_请给出执行一趟堆排序后的结 果。(详细画出堆的形态)

请给出执行一趟堆排序后的结 果。(详细画出堆的形态)

堆排序:

特点
        堆排序(HeapSort)是一树形选择排序。堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,

利用完全二叉树中双亲结点和孩子结点之间的内在关系(参见二叉树的顺序存储结构),在当前无序区中选择关键字最大(或最小)的记录

堆排序与直接选择排序的区别直接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字

最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留

这些比较结果,所以后一趟排序时又重复执行了这些比较操作。


        注:堆排序可通过树形结构保存部分比较结果,可减少比较次数。
算法分析
       堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用Heap实现的。
       堆排序的最坏时间复杂度为O(nlogn)。堆序的平均性能较接近于最坏性能。
        由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。
        堆排序是就地排序,辅助空间为O(1),
        它是不稳定的排序方法。

实在如下:

  1. /*
  2. Filename:myHeapsort.cpp
  3. Author: xiaobing
  4. E-mail: xiaobingzhang29@gmail.com
  5. Date: 2013-08-27
  6. */
  7. #include<iostream>
  8. #include<string>
  9. #include<algorithm>
  10. #include<cstdlib>
  11. #define N 10
  12. using namespace std;
  13. void swap(int *a, int *b){
  14. int temp = *a;
  15. *a = *b;
  16. *b = temp;
  17. }
  18. /*
  19. 堆排序实现
  20. n个关键字序列Kl,K2,…,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质):
  21. (1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),当然,这是小根堆,大根堆则换成>=号。
  22. k(i)相当于二叉树的非叶结点,K(2i)则是左孩子,k(2i+1)是右孩子
  23. 若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:
  24. 树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
  25. 实现原理:
  26. 1。开始时,需将数组建立为一个堆,使得其满足所有的非叶节点的值都大于等于(或小于等于)其左右
  27. 孩子节点的值,这样的效果使得第一个节点,即根节点总是最大的元素。
  28. 2.从最后一个数组元素开始与数组第一个元素交换数据,交换一次后,再创新建立堆,但堆的长度减1,直到
  29. 数组长度变为1为止,这样就排序完成
  30. 注:使得每个非叶节点的值都大于等左右孩子节点的值,是实现由小到大排序
  31. 相反,是实现由大到小排序。
  32. */
  33. /*
  34. *@prama arr 待排序的数组
  35. @prama i 待开始调整的位置
  36. @prama length 调整的范围,当然,开始时是数组长度,但后面会越来越小直到为1
  37. * */
  38. void heapAdjust(int arr[], int i, int length){
  39. int temp, child; //定义了一个temp来存储调整的值,child来指定该调整值的孩子位置
  40. //缓存上应该调整的值
  41. for(temp = arr[i]; 2 * i + 1 < length; i = child){
  42. //孩子为左孩子
  43. child = 2 * i + 1;
  44. //如果满足child + 1 < length 这个是确定不会越界
  45. //这样就观察左孩子与右孩子谁大,若右孩子大,则child 为右孩子,child + 1
  46. if(child + 1 < length && arr[child + 1] > arr[child]){
  47. child++;
  48. }
  49. //如果孩子节点比父节点大,因为刚才已经确定了arr[child]是左右孩子中的大着
  50. //更新父节点为大值
  51. if(arr[child] > temp){
  52. arr[i] = arr[child];
  53. } else { //如果父节点是大者,则已经调整好,所以退出循环
  54. break;
  55. }
  56. //若更新后,则交换值,若没有更新,则已经退出了,不能执行到此
  57. arr[child] = temp;
  58. }
  59. }
  60. /*
  61. @prama arr 待排序的数组
  62. @prama length 数组的长度
  63. */
  64. void heapsort(int arr[], int length){
  65. int i;
  66. //实现第一步
  67. /*
  68. 这里从i = length / 2 -1开始调节,原理是:
  69. i = length /2 - 1是数组元素,以0为根,顺序构造完全二叉树时,最后一个非叶节点
  70. 因此,以该点开始调节,逐渐减i,把最后一排的元素的最大值都替换为其父节点倒数
  71. 第二排的值,逐渐减i,到了倒数第三排,然后把倒数第二排的最大值又替换为父节点
  72. 倒数第三排的值,以此类推,最终根元素的值就是最大的,当然,如果要从大到小排序
  73. 则可以让根的值为最小值,
  74. 不明白时,可以把完全二叉树画出来看一下,就清晰了
  75. */
  76. for(i = length / 2 - 1; i >= 0; i--){
  77. heapAdjust(arr, i, length);
  78. }
  79. //实现第二步
  80. /*
  81. *这里是从最后元素开始调整,不断缩小范围,直到第一个元素为止
  82. */
  83. for(i = length - 1;i > 0;i--){
  84. //总是把第一个元素和后面的元素进行交换,因为第一个元素总是最大的(或最小的)
  85. swap(&arr[i], &arr[0]);
  86. //交换一次后,应该再调整一次,寻找其余的元素的最大值(或最小值)存在根为止,即0位置
  87. heapAdjust(arr, 0, i - 1);
  88. }
  89. }
  90. void print(int arr[], int n){
  91. int i;
  92. for(i = 0; i < n;i++){
  93. cout<<arr[i]<<" ";
  94. }
  95. cout<<endl;
  96. }
  97. int main(){
  98. int arr[N] = {213,354,45,123,4,6,57,7,8,56};
  99. heapsort(arr, N);
  100. print(arr, N);
  101. return 0;
  102. }
转载请附上地址: http://blog.csdn.net/xiaobing_blog/article/details/10400661

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

闽ICP备14008679号