• TopK、最小堆、随机排序、快排问题


    盗用下别人的标题,把我的顶上去,别人说的虽然有道理,但是缺乏实践。决定自己写个例子,实测结果如下:

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

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

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

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


    N个随机数取最大的K个和第K个其实是一个问题,区别在于K的位置。
    当K很小,N很大时,用小顶堆。当K接近N的一半时,用快排。

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

    原因:

    1.速度确实快。

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

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

    4.快排需要把所有数加到缓存里,而数据太大,查询过程中导致高速缓存置换,反而更慢了

      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 }
  • 相关阅读:
    Pandas+Numpy 数据中空值的处理操作:判断、查找、填充及删除
    跑新项目时遇到的报错及解决方案
    Java Stream流排序null以及获取指定条数数据
    通信端口Com口被占用的原因分析
    查询sq字段逗号分隔的方式
    IIS及时回收
    oracle中创建sequence指定起始值
    js 面向对象代码
    C# 将html实体编码转换到正常字符 & #40;格式
    DataTable列查询加排序
  • 原文地址:https://www.cnblogs.com/workharder/p/12585363.html
Copyright © 2020-2023  润新知