堆 求最数大最小前k个sh

来源:互联网 发布:windows ndk下载 编辑:程序博客网 时间:2024/06/07 17:28
用堆在海量数据中找出最大或最小的k个数,效率非常高。

1、在一组数据中找出最小的k个数
解题思路:
    要找出最小的k个数,我们可以先用这组数据中的k个数构建一棵“最大堆”,然后再将剩下的元素与堆顶元素相比。如果大于堆顶元素,则不做处理,继续向下比较。如果小于堆顶元素,则将堆顶元素与这个元素交换,然后再恢复堆序,继续向下比较。这样的话最后这个堆里面保存的就是最小的k个数。
例:在{10,16,18,12,11,13,15,17,14,19}里面找出最小的4个数 
1、用前四个数构造一颗最大堆


(2、用剩下的数与堆顶元素进行比较,如图:


2、在一组堆中找出最大的前k个数
与找最小的数是相同的道理,不过找最大的数时要建立一个k个数的最小堆。

时间复杂度分析:
建立一个k个数的堆:O(k*lgk)
向后比较:O((N-k)*lgk)

时间复杂度为:O(N*lgK)


[cpp] view plain copy
  1. //代码  
  2. #pragma once  
  3. #include<vector>  
  4. #include<cassert>  
  5. using namespace std;  
  6.   
  7.   
  8. template<typename T>  
  9. struct SmallNum                  //求最小的数,建最大堆  
  10. {  
  11.     bool operator()(const T& l,const T& r)  
  12.     {  
  13.         return l < r;  
  14.     }  
  15. };  
  16.   
  17. template<typename T>  
  18. struct GreatNum                 //求最大的数,建最小堆  
  19. {  
  20.     bool operator()(const T& l,const T& r)  
  21.     {  
  22.         return l>r;  
  23.     }  
  24. };  
  25.   
  26.   
  27.   
  28. template<typename T,class Compare=SmallNum<T>>      //默认求最小的k个数  
  29. class HeapSearch  
  30. {  
  31. public:  
  32.     HeapSearch()  
  33.     {}  
  34.     HeapSearch(T* a, int size,int k)  
  35.     {  
  36.         assert(size>=k);  
  37.         assert(k>0);  
  38.         //建一个k个数的堆,如果求最小的k个数则建最大堆,反之建最小堆  
  39.         _a.reserve(k);  
  40.         for (int i = 0; i < k; ++i)  
  41.         {  
  42.             _a.push_back(a[i]);  
  43.         }  
  44.   
  45.         for (int i = (k - 2) / 2; i >= 0; --i)  
  46.         {  
  47.             //向下调整算法  
  48.             AdjustDown(i,k);  
  49.         }  
  50.   
  51.         FindKNum(a,size,k);  
  52.     }  
  53.   
  54.     void Display()  
  55.     {  
  56.         for (size_t i = 0; i < _a.size(); i++)  
  57.         {  
  58.             cout << _a[i] << " ";  
  59.         }  
  60.         cout << endl;  
  61.     }  
  62.   
  63. protected:  
  64.     void AdjustDown(int root,int k)  
  65.     {  
  66.         assert(!_a.empty());  
  67.         int parent= root;    //最后一个非叶子结点  
  68.         int child = parent * 2 + 1;      //求左孩子结点的下标  
  69.         while (child<k)  
  70.         {  
  71.             if ((child + 1) < k&&Compare()(_a[child],_a[child+1]))  
  72.                 child++;  
  73.             if (Compare()(_a[parent], _a[child]))  
  74.             {  
  75.                 swap(_a[parent],_a[child]);  
  76.                 parent = child;  
  77.                 child = parent * 2 + 1;  
  78.             }  
  79.             else  
  80.             {  
  81.                 break;  
  82.             }  
  83.         }  
  84.     }  
  85.   
  86.     void  FindKNum(T*a ,int size,int k)  
  87.     {  
  88.         for (int i = k; i < size;i++)  
  89.         {  
  90.             if (Compare()(a[i], _a[0]))  
  91.             {  
  92.                 _a[0] = a[i];  
  93.                 AdjustDown(0,k);  
  94.             }  
  95.         }  
  96.     }  
  97. private:  
  98.     vector<T> _a;  
  99. };  
阅读全文
0 0
原创粉丝点击