Partially sorting an array C

时间:2016-10-15 17:15:48

标签: c arrays qsort

I have an array which looks like this:

int array[] = {4.53, 3.65, 7.43, 9.54, 0.72, 0.0}

I am just wondering what method I can use to partially sort this array to bring the top three biggest doubles to the front. I am looking for the most efficient method to get the top three highest numbers in this array.

So far I have been using qsort, but I am just looking for another method to do this which could be even faster. I know that qsort is O(nlogn) for best cases and O(n^2) for worst cases, but is there an even more efficient method to achieve this problem? What I mean by efficient is just a faster way to do it, better than O(nlogn).

Any help would be great

4 个答案:

答案 0 :(得分:3)

简单地保持第一,第二,第三。

   first =  array[0];
   second = array[1];
   third = array[2];

   /* scratch sort for three elements */
   if(first < second)
     swap(first, second);
  if(first < third)
     swap(first, third);
  if(second < third)
     swap(second, third);

  /* now go through, bubbling up if we have a hit */ 
  for(i=3;i<N;i++)
  {
      if(third < array[i])
      {
         third = array[i];
         if(second < third)
         {
            swap(second, third);
            if(first < second)
              swap(first, second);
         }
      }
  }     

我不会尝试扩大到k = 4。我认为三是关于硬编码的限制。随着k变大,你需要转向正式的方法。

这并没有回答你实际问过的问题,这是如何进行部分排序,但似乎是你想要的。

如果您希望进行部分排序,可以使用快速排序,只需在枢轴超出您感兴趣的界限时提早返回。所以我们的第一个支点分为五个,两个。忽略最后两个,只实际执行最后五个的子排序。虽然它会比快速排序更快,但它不会成为改变游戏规则的人。如果您可以在第k项上获得保守的上限(例如,它在最小值和平均值之间总是最多为25%),您可以快速消除大部分数据。如果你弄错了,那只是另一两次。

使用快速排序方法

  int sortfirstk_r(int *array, int N, int k)
  {
     int pivot = 0;
     int j = n -1;
     int i = 1;

     while(i <= j)
     {
        if(array[pivot] < array[i])
          swap(array[i], array[j--])
        else
          i++;

     }
     sortfirstk_r(array, i, k < i ? k : i);
     if(i < k)
       sortfirstk_r(array +i, N -i, k - i); 

  }

(未经测试,在稍微棘手的排序逻辑中可能存在错误)。

然而,我们天真地使用第一个元素作为支点。如果我们对大型数据集进行排序,并且它具有正态分布,并且我们想要前1%,则z得分为2.326。多花点时间让我们得到一些抽样误差,然后我们首先使用一个枢轴设置,比平均值高出2.3个标准偏差。然后我们将分布分为两组,前1%加一点,其余的。我们不需要进一步处理剩下的事情,只需对顶级组进行排序。

答案 1 :(得分:2)

对于您的特定问题,最快的方法是执行类似于下面的操作,因为您只需要三个元素:(使用优先级队列或不同的数据结构可能更快,但速度不会非常明显)< / p>

#include"stdio.h"
void moveThreeMaxToFront(double * arr, int length);
void moveMaxToFront(double*arr, int length);
int main() {
  int i;
  double meh[]={ 5,3,1,7,2,9,11};
  moveThreeMaxToFront(meh, 7);
  for(i=0; i<7; i++)
    printf("%f \n", meh[i]);
}
void moveThreeMaxToFront(double * arr, int length) {
  for(int i=0; i<3; i++)
    moveMaxToFront(arr++, length-i);
}
void moveMaxToFront(double* arr, int length) {
  int i;
  for(i=1; i<length; i++) {
    if(arr[i]>arr[0]) {
      double tmp=arr[i];
      arr[i]=arr[0];
      arr[0]=tmp;
    }
  }
}

但是,如果k变得非常大,以实现Quickselect或使用我认为实现快速选择的partial_sort方法,则可能会更快。然而,给定情况的快速选择算法的平均常数约为3.4-4.4,略大于(3)以上的常数。另请注意,quickselect的平均运行时间为O(n)。使用中位数3可以保证运行时间,但不建议这样做,因为它会显着增加平均常数。 Intro-select正确处理这个问题,以防止最坏情况下的quickselect,同时保留其平均情况。

答案 2 :(得分:0)

If we are supposed to find out the three largest number then we can run findMax method three times and once a maximum is found replace appropriate index (1, 2 or 3) with maximum in array. This way we leave you with array will 3 largest elements at start of array in c * O(n) time-complexity.

Note: I used fact that you have to find first three maximum doubles

double findMax(double arr[i], double prevMax){
    double maximum = -100000000000;
    for(int i = 0; i < arr.length; i++){
        if(arr[i] < prevMax)
        maximum = max(arr[i], maximum);
    }
    return maximum;
 }

答案 3 :(得分:0)

我建议基数排序它是这种情况下最有效的排序方法,并且具有复杂度O(n)。当找到三个最大数字时,你甚至可以稍微改变它。 你可以找到 - 理解基数简短: https://www.cs.usfca.edu/~galles/visualization/RadixSort.html