topK问题最小堆和快排哪个快

Posted 生命不息,奋斗不止。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了topK问题最小堆和快排哪个快相关的知识,希望对你有一定的参考价值。

最近一直纠结这个问题。看了很多帖子,决定自己写个例子,实测结果如下:

总数1万个取最大100,快排略快,最小堆偶尔快。

总数10万个取最大100,最小堆略快,快排偶尔快。

总数100万个取最大100,最小堆完胜,快排没戏,而且最小堆大概快了2倍。

总数1000万个取最大100,最小堆完虐,快排没戏,而且最小堆快了大概2倍。

结论:最小堆比快排优秀。

原因:

1.速度确实快。

2.最小堆不需要打乱原数据顺序,而快排会打乱。(并不是快的原因,而是最小堆的优点)

3.如果内存有限,无法加载所有数据,则最小堆快。

 

技术图片
  1 #include <vector>
  2 #include <iostream>
  3 #include <time.h>
  4 #include <random>
  5 using namespace std;
  6 
  7 //改良版部分区域快排
  8 int Partition(vector<int>& arr, int low, int high)
  9 {
 10     int pivokey = arr[low];//因为arr已经是随机数了,不需要再有分区算法,反而会慢
 11     while (low < high)
 12     {
 13         while (low < high && arr[high] <= pivokey) --high;
 14         arr[low] = arr[high];
 15         while (low < high && arr[low] >= pivokey) ++low;
 16         arr[high] = arr[low];
 17     }
 18     arr[low] = pivokey;
 19     return low;
 20 }
 21 int TopK_Qsort(vector<int>& arr, int start, int end, int k)
 22 {
 23     int index = 0;
 24     if (start < end)
 25     {
 26         index = Partition(arr, start, end);
 27         if (index < k)//还要从index的右边找k-index个数
 28         {
 29             index = TopK_Qsort(arr, index + 1, end, k);
 30         }
 31         else if (index > k)//k个数都在Index的左边
 32         {
 33             index = TopK_Qsort(arr, start, index - 1, k);
 34         }
 35     }
 36     return index;
 37 }
 38 
 39 //小顶堆化
 40 void HeapAdjust(vector<int>& nums, int pos)
 41 {
 42     for (int i = 2 * pos + 1; i < nums.size(); i = 2 * i + 1)
 43     {
 44         if (i<nums.size() - 1 && nums[i]>nums[i + 1])
 45             i++;
 46         if (nums[i] >= nums[pos])
 47             break;
 48         swap(nums[i], nums[pos]);
 49         pos = i;
 50     }
 51 }
 52 void TopK_Heap(vector<int>& arr, int k)
 53 {
 54     if (arr.size() <= k)
 55         return;
 56     vector<int> box;
 57     box.resize(k);
 58     for (int i = 0; i < k; i++)
 59         box[i] = arr[i];
 60     for (int i = box.size() / 2; i >= 0; i--)
 61         HeapAdjust(box, i);
 62     for (int i = k; i < arr.size(); i++)
 63     {
 64         if (arr[i] > box[0])
 65         {
 66             box[0] = arr[i];
 67             HeapAdjust(box, 0);
 68         }
 69     }
 70 }
 71 
 72 int main()
 73 {
 74     int nCounterA = 0;    //代表小顶堆胜出次数
 75     int nCounterB = 0;    //代表快排胜出次数
 76     int nCounterC = 0;    //平手
 77     for (int t = 750; t<= 770;++t)//t是随机种子,保证每次待排序列表里是新的随机数
 78     {
 79         default_random_engine e;
 80         e.seed(t);                
 81 
 82         int nTotal = 10000;            //总共有多少个数
 83         int nTopK = 100;                //前TOPK个数
 84         //-------------------填充随机数-----------------------
 85         vector<int> vecQsortResource;
 86         vecQsortResource.reserve(nTotal);
 87         vector<int> vecHeapResource;
 88         vecHeapResource.reserve(nTotal);
 89         for (int i = nTotal; i > 0; i--)
 90         {
 91             vecQsortResource.push_back(e() % nTotal);
 92         }
 93         vecHeapResource = vecQsortResource;
 94 
 95         //-------------------两种算法开始计算-----------------------
 96         clock_t start, finish;
 97         start = clock();
 98         TopK_Heap(vecHeapResource, nTopK);
 99         finish = clock();
100         double nRes1 = (double)(finish - start);
101         //cout << "
小顶堆的运行时间为" << nRes1 / CLOCKS_PER_SEC << "秒!" << endl;
102 
103         start = clock();
104         TopK_Qsort(vecQsortResource, 0, nTotal - 1, nTopK - 1);
105         finish = clock();
106         double nRes2 = (double)(finish - start);
107         //cout << "
快排的运行时间为" << nRes2 / CLOCKS_PER_SEC << "秒!" << endl;
108 
109         if (nRes1 < nRes2)
110         {
111             nCounterA++;
112         }
113         else if (nRes1 > nRes2)
114         {
115             nCounterB++;
116         }
117         else
118         {
119             nCounterC++;
120         }
121     }
122 
123     cout << nCounterA << endl;    //代表小顶堆胜出次数
124     cout << nCounterB << endl;    //代表快排胜出次数
125     cout << nCounterC << endl;    //平手
126     return 0;
127 }
测试代码

 

以上是关于topK问题最小堆和快排哪个快的主要内容,如果未能解决你的问题,请参考以下文章

topK问题

topK问题

深夜来到校花学姐家,帮她解决了TopK,她竟然......

topK问题

排序算法的简单实现(冒泡和快排)

排序算法之冒泡和快排