排序数组以找到前20个最小数字

时间:2011-10-12 13:07:47

标签: arrays algorithm hash

  

可能重复:
  Algorithm to find k smallest numbers in array of n items

如何在一个非常大的阵列中找到前20个最小元素?

4 个答案:

答案 0 :(得分:2)

您有两个选择

  1. 对数组进行排序并拉出小端的20个元素(取决于您对数组进行排序的方向,对吗?)
  2. 保持数组元素的排序集(可能不是由于数组的非唯一性而设置)。添加数组中的前20个元素。每当你发现一个小于'good set'中的最高元素时,用这个新元素替换最高元素。
  3. 第二个可能看起来较慢,但它实际上取决于数组的大小。你可以通过一次通过数组来完成它,所以最好在80亿或者其他的数组上执行此操作。

    编辑:第一个算法是O(n lg n)。第二个算法是O(k n),其中k在这种情况下是20(你想要前20个)。因此,当lg n > 20n > 2^20n > ~1 million时,第二种算法会更快。所以,如果你的人数少于一百万,那么你的排序会更好。如果你有超过一百万的话,你最好不要制作外部名单并且一次通过。

答案 1 :(得分:1)

如果阵列真的很大,那么排序会花费很长时间和很多空间。

你需要什么:

  • 将数组A的前20个元素复制到新数组B中。

  • 排序B

  • 遍历数组A并检查每个元素是否小于 B [19]

  • if yes =>将其添加到B,排序B,删除B

  • 的最后一个元素

答案 2 :(得分:0)

不确定它是否是最佳的,但您可以尝试运行20次迭代排序。

答案 3 :(得分:0)

看在上帝的份上,不要对整个阵列进行排序。将大小为20的数组初始化为大数组的前20个元素。现在,逐步执行大数组,将小数组中的任何元素替换为您正在考虑的大数组中的元素。这是O(n);比任何基于比较的排序都要好,并且可能比线性排序更有效(具有良好的实现)(无论如何都不能总是使用)。

编辑:

因此,出于好奇,我实现了线性算法的简单版本,并将其与C ++ STL sort()函数进行了比较。以下是我的结果 - 他们表明,正如我所料,线性算法平均总是优于排序 - 即使在线性算法的理论最坏情况下,你需要一个更大的数组才能获胜。以下是我的表现数据:

        N        Sort      Linear      Common
       32,        378,        170,        116
       64,        831,        447,        237
      128,       1741,       1092,        424
      256,       5260,       2211,        865
      512,      10955,       5944,       1727
     1024,      20451,      10529,       3584
     2048,      38459,      21723,       7011
     4096,      77697,      41023,      14136
     8192,     150630,      82919,      28083
    16384,     311593,     166740,      55978
    32768,     648331,     334612,     111891
    65536,    1329827,     673030,     224665
   131072,    2802540,    1342430,     449553
   262144,    5867379,    2717356,     896673
   524288,   12082264,    5423038,    1798905
  1048576,   25155593,   10941005,    3658716
  2097152,   62429382,   24501189,    8940410
  4194304,  120370652,   44820562,   14843411

N是问题大小,Sort是以微秒为单位的排序时间,Linear是以微秒为单位的线性算法时间,Common是在每次测试之前随机化数组所花费的时间。请注意,要使在Sort和Linear算法中花费的时间,您需要从第二列中的值中减去第四列中的值。如果你希望我这样做,我会很高兴。很明显,线性比排序更快。每个N测试100次,这些是所有100次测试的总数(总计时间)。这是我使用的代码:

  void randomize(unsigned char *data, int n) {
     for(int i = 0; i < n; i++)
        data[i] = (unsigned char)(rand() % 256);

  }

  void sorttest(unsigned char *data, int n) {
     unsigned char results[20];
     sort(data, data + n);
     for(int i = 0; i < 20; i++)
        results[i] = data[i];
  }

  void scantest(unsigned char *data, int n) {
     unsigned char results[20];
     for(int i = 0; i < 20; i++)
        results[i] = data[i];

     for(int i = 20; i < n; i++)
        for(int j = 0; j < 20; j++)
           if(data[i] < results[j]) {
              results[j] = data[i];
              break;
           }
  }


  void dotest(int n)
  {
     unsigned char *data = (unsigned char*)malloc(n);
     timeval t1, t2, t3, t4, t5, t6;

     gettimeofday(&t1, 0);
     for(int i = 0; i < 100; i++) {
        randomize(data, n);
        sorttest(data, n);
     }
     gettimeofday(&t2, 0);


     gettimeofday(&t3, 0);
     for(int i = 0; i < 100; i++) {
        randomize(data, n);
        scantest(data, n);
     }
     gettimeofday(&t4, 0);

     gettimeofday(&t5, 0);
     for(int i = 0; i < 100; i++)
        randomize(data, n);
     gettimeofday(&t6, 0);

     int dt1 = 1000000*(t2.tv_sec - t1.tv_sec) + (t2.tv_usec - t1.tv_usec);
     int dt2 = 1000000*(t4.tv_sec - t3.tv_sec) + (t4.tv_usec - t3.tv_usec);
     int dt3 = 1000000*(t6.tv_sec - t5.tv_sec) + (t6.tv_usec - t5.tv_usec);
     printf("%10d, %10d, %10d, %10d\n", n, dt1, dt2, dt3);
     free(data);
  }

  int main() {
     srand(time(0));
     for(int i = 32; i < 5000000; i*=2) dotest(i);
     return 0;
  }

我邀请任何声称排序同样好的人指出我如何修改此基准以更公平/正确,以便排序排在最前面。不完全是;你可以自己尝试一下。