【算法导论】排序 (二):堆排序

  • Post author:
  • Post category:其他



四、


(1)堆排序

第一次听堆排序是在107lab听忠哥讲的,但是没讲怎么实现。那时刚看了数据结构的二叉树,还以为要通过指针建立二叉树的方式来实现,觉得挺难的。

其实堆排序实现没有想象中的那么难。

“堆”这个词最初是在堆排序中提出来的,但后来就逐渐指”废料收集储存区“,就像程序设计语言Lisp和Java中所提供的设施那样。我们这里的堆数据结构不是废料收集存储区。

堆排序的运行时间与归并排序一样为O(n lg n),  但是一种原地(in place)排序。


(二叉)堆

数据结构是一种数组对象,它可以被视为一棵完全二叉树。

对于一个数组arr[ ]={16,14,10,8,7,9,3,2,4,1}的存储数据结构如下图:


在这个结构中,对于每一个根节点i ,要保证它都比他的子节点大

我们可以用一个数组A【1…length【A】】来表示这个完全二叉树结构。 其中A【1】为根节点1

首先问题是求父节点、左儿子、右儿子的坐标,通过观察我们可以用宏或者内联函数实现:



  1. // 根据某节点下标i, 计算父节点、左儿子、右儿子的下标





  2. inline




    int


    Parent(


    int


    i) {


    return


    i>>1; }



  3. inline




    int


    Left(


    int


    i) {


    return


    i<<1; }



  4. inline




    int


    Right(


    int


    i) {


    return


    (i<<1)|1; }


    //位运算乘2后,结果是偶数所以最后一位一定是0, 所以|1将会把最后一位变成1,从而实现加1的效果




无论是《C++ primer》还是《Effective C++》,都讲过宏的缺陷,用内联函数是个更好的选择。位运算做乘除的速度更快。

至于算法演示过程在《算法导论》上讲得很详细,不再赘述。

堆排序过程需要以下三个函数:



1、Max-Heapify(A,i)

: 保持堆的性质,让A【i】在最大堆中“下降”,使以i节点为根的字数成为最大树



2、Buid-Max-Heap(A)




自底向上将数组A【1…n】变成一个最大堆









3、Heap-Sort(A): 进行堆排序










C++代码实现:(数组A是下标1开始的)



  1. /*       算法导论 第6章 堆排序    */





  2. #include<cstdio>





  3. #include<algorithm>





  4. using




    namespace


    std;





  5. // 根据某节点下标i, 计算父节点、左儿子、右儿子的下标





  6. inline




    int


    Parent(


    int


    i) {


    return


    i>>1; }



  7. inline




    int


    Left(


    int


    i) {


    return


    i<<1; }



  8. inline




    int


    Right(


    int


    i) {


    return


    (i<<1)|1; }


    //位运算乘2后,结果是偶数所以最后一位一定是0, 所以|1将会把最后一位变成1,从而实现加1的效果







  9. inline




    void


    Swap(


    int


    &a,


    int


    &b) {


    if


    (a!=b){a^=b; b^=a; a^=b;} }





  10. /*



  11. 堆排序的基本过程函数:






  12. MaxHeap(A,len,i): 其运行时间为O(lgN),是保持最大堆性质的关键



  13. BuidMaxHeap(A): 过程,以线性时间运行,可以在无需的输入数组基础上构造出最大堆



  14. HeapSort(A): 对一个数组原地进行排序






  15. */






  16. // 保持堆的性质,使以i为根的子树成为最大堆





  17. void


    MaxHeap(


    int


    *A,


    int


    heap_size,


    int


    i){




  18. int


    l,r,max;


  19. l = Left(i);

  20. r = Right(i);



  21. if


    (l<=heap_size && A[l]>A[i])


  22. max=l;


  23. else




  24. max=i;



  25. if


    (r<=heap_size && A[r]>A[max])


  26. max=r;



  27. if


    (max!=i){


  28. Swap(A[i],A[max]);

  29. MaxHeap(A,heap_size,max);

  30. }

  31. }



  32. // 建堆,自底向上用MaxHeap将整个数组变成一个最大堆





  33. void


    BuidMaxHeap(


    int


    *A,


    int


    heap_size){




  34. for


    (


    int


    i=heap_size>>1; i>=1; –i){


  35. MaxHeap(A,heap_size,i);

  36. }

  37. }



  38. // 堆排序





  39. void


    HeapSort(


    int


    *A,


    int


    heap_size){



  40. BuidMaxHeap(A,heap_size);


  41. int


    len=heap_size;



  42. for


    (


    int


    i=heap_size; i>=2; –i){


  43. Swap(A[1], A[i]);

  44. –len;

  45. MaxHeap(A,len,1);

  46. }

  47. }



(2)优先级队列


C++ STL中的priority_queue就是用这种方法来实现的。


1、Heap-MaxiNum(A): 取出堆中的最大值









2、Heap-Extract-Max(A): 删除堆中的最大值并返回它的值









3、Heap-Increase-Key(A,i,key):将节点i的值增加到key,这里key要比i节点原来的数大。









4、Max-Heap-Insert(A, key):   插入一个新元素key到堆中,要用到3的函数







C++实现:




  1. // 优先级队列






  2. int


    HeapMaxNum(


    int


    *A){



  3. return


    A[1];


  4. }



  5. int


    HeapExtractMax(


    int


    *A,


    int


    heap_size){



  6. if


    (heap_size>=1){



  7. int


    max=A[1];


  8. A[1] = A[heap_size];

  9. –heap_size;

  10. MaxHeap(A,heap_size,1);


  11. return


    max;


  12. }

  13. }



  14. bool


    HeapIncreaseKey(


    int


    *A,


    int


    i,


    int


    key){



  15. if


    (key<A[i])



  16. return




    false


    ;


  17. A[i] = key;


  18. while


    (i>1 && A[Parent(i)]<A[i]){


  19. Swap(A[i],A[Parent(i)]);

  20. i = Parent(i);

  21. }


  22. return




    true


    ;


  23. }



  24. void


    MaxHeapInsert(


    int


    *A,


    int


    key,


    int


    heap_size){


  25. ++heap_size;

  26. A[heap_size] = -2147484646;

  27. HeapIncreaseKey(A,heap_size,key);

  28. }





——      生命的意义,在于赋予它意义。















原创









http://blog.csdn.net/shuangde800











By   D_Double












版权声明:本文为shuangde800原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。