堆排序算法

来源:互联网 发布:知乎一小时 epub 编辑:程序博客网 时间:2024/06/05 00:26

1.概述
  1991年计算机先驱将获得者、斯坦福大学计算机科学系教授Robert W.Floyd和J. Williams在1964年共同发明了著名的Heap Sort算法。
  堆排血实质上就是将要进行排序的序列Arr[1..n]看做是一棵完全二叉树的存储结构,堆则是满足如下性质的完全二叉树:树中任一非
  叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。(如果按照数组中线性存储该树,可得到一个既不是单调
  递增也不是单调递减的序列)
  
  (1)堆排序与直接选择排序的区别
  直接排序的缺点:直接选择排序过程中,为从Arr[1..n]中选择出关键字最大的记录,必须进行n-1次比较,然后在Arr[2...n]中选出关
  键字最大的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面n-1比较中已经做成的,但是由于前一趟
  比较过程中未保留这些比较结果,所以后一趟排序执行了这些比较操作。
  堆排序:堆排序可以通过树型结构保存部分比较结果,从而可以大大减少比较的次数。

  (2)大堆排序的基本思想
  首先将Arr[1..n]建成一个大根堆,此堆为初始的无序区。再将关键字最大的记录Arr[i]和无序区的最后一个记录Arr[n]交换,由此得到
  了一个新的无序区Arr[1..n-i]和有序区Arr[...n],且满足Arr[1..n-i]<Arr[...n]
  由于交换后新的根Arr[i]可能违反堆性质,故应将当前无序区Arr[1..n-i]调整为堆,重复执行第二部的操作,最后直到无序区只有一个
  元素为止。
  
  (3)该算法的分析
  堆排序法的时间主要花费在将原始序列调整为一个初始堆积以及排序过程中不断将移走最大值元素以后剩余的那些元素重新调整为一个新
  的堆两部上。所以,该方法对于n较大的数据元素序列是很合适的。

2. 编辑环境
  NetBeans C++ 6.5
  Window XP
  
3.问题概述及算法实现
  问题:从十亿个数中取出前十个最大的数。(只想到用该算法去实现了,如果有更好的实现方法,可以share)
 程序:

[cpp] view plaincopyprint?
  1. /* 
  2. 堆排序,数组元素下标从1开始到size 
  3. */  
  4.   
  5. // 从第m个节点开始堆化   
  6. static void HpShift(int* arr, const int m, const int size)  
  7. {  
  8.     if (NULL == arr || size <= 0)  
  9.     {  
  10.         return;  
  11.     }  
  12.   
  13.     int t = arr[m];  
  14.     int i = m * 2; // 指示孩子节点  
  15.     while (i <= size)  
  16.     {  
  17.         // 找出最大的孩子节点   
  18.         if (i < size && arr[i] < arr[i + 1])  
  19.         {  
  20.             ++i;  
  21.         }  
  22.   
  23.         // 已经堆队行   
  24.         if (t >= arr[i])  
  25.         {  
  26.             break;            
  27.         }  
  28.   
  29.         // shift   
  30.         arr[i / 2] = arr[i];  
  31.         i *= 2;  
  32.     }  
  33.   
  34.     arr[i / 2] = t;  
  35. }  
  36.   
  37. void HpSort(int* arr, const int size)  
  38. {  
  39.     if (NULL == arr || size <= 0)  
  40.     {  
  41.         return;  
  42.     }  
  43.   
  44.     // 自底向上堆化   
  45.     int m = size / 2;  
  46.     for (; m >= 1; --m )  
  47.     {  
  48.         HpShift(arr, m, size);  
  49.     }  
  50.   
  51.     // 无序区 + 有序区   
  52.     int t;  
  53.     for (m = size; m >= 1; --m)  
  54.     {  
  55.         t = arr[1];  
  56.         arr[1] = arr[m];  
  57.         arr[m] = t;  
  58.   
  59.         // 无序区堆化   
  60.         HpShift(arr, 1, m - 1);       
  61.     }  
  62. }  

调用示例

[cpp] view plaincopyprint?
  1. #include <iostream>   
  2. #include "demo.h"   
  3.   
  4. template<typename T>  
  5. void PrintArr(T* arr, int const size);  
  6. int main()  
  7. {  
  8.     std::cout << "www.baidu.com" << std::endl;  
  9.       
  10. //  int a[]={-1, 33, 32, 35, 31, 34};   
  11. //  std::cout << find_lost(a,6) << std::endl;     
  12.   
  13.   
  14.     // 堆排序   
  15.     int const size = 10;  
  16.     int arr[size] = {-1, 26, 5, 77, 1, 61, 11, 59, 15, 48};  
  17.     PrintArr(arr, size);      
  18.     HpSort(arr, size - 1);  
  19.     PrintArr(arr, size);  
  20.       
  21.     return EXIT_SUCCESS;  
  22. }  
  23.   
  24. template<typename T>  
  25. void PrintArr(T* arr, int const size)  
  26. {  
  27.     if (NULL == arr || size <= 0)  
  28.     {  
  29.         return;  
  30.     }  
  31.   
  32.     int ind = 1;  
  33.     for (ind = 1; ind < size; ++ind )   
  34.     {  
  35.         std::cout << "=====";  
  36.     }  
  37.     std::cout << std::endl;  
  38.   
  39.     for (ind = 1; ind < size; ++ind)  
  40.     {  
  41.         std::cout << arr[ind] << " ";  
  42.     }  
  43.     std::cout << std::endl;  
  44.     for (ind = 1; ind < size; ++ind )   
  45.     {  
  46.         std::cout << "=====";  
  47.     }  
  48.     std::cout << std::endl;  
  49. }  

原创粉丝点击