Qsorting一个多维数组

时间:2013-11-14 08:37:28

标签: c arrays sorting multidimensional-array quicksort

我目前正在研究一种算法,它要求我的多维数组(当前为3维)按第一项和第二项的和值进行排序。具体做法是:

(要交换的项目i和j的条件)

if ((Array[i][1]+Array[i][2]) > (Array[j][1]+Array[j][2])) return 1;

出于测试目的,我决定使用select sort。但是,我的算法需要在5秒内完成所有魔法。如果它有大约200 000个项目,则选择对自身进行排序需要大约10秒来对这样的数组进行排序。

我决定使用更好的算法,因为我对其余程序非常有信心。我知道unix系统包含一个内置的快速排序功能qsort(可通过终端中的 man qsort 获得)。但是,我不知道如何实现它。

我的想法是创建另一个数组,一维(1D),长度相同,包含主数组中项目的索引。通过这个,我可能只能排序辅助1D数组,其中第一项将具有最小总和的主数组中的项目索引,第二项将具有第二最小,依此类推。

但是,我该怎么办呢? Qsort函数需要提供比较函数,以决定是否交换。如果我确实创建了自己的比较函数(就像我在问题的开头所说的那样),当主要数组仅在 main 该函数,因此无法通过同一文件中的其他函数访问?

我会很高兴有任何提示或技巧如何解决这个问题。我也不热衷于使用qsort。如果您认为另一种排序算法可以做得更好,请告诉我。

非常感谢

1 个答案:

答案 0 :(得分:1)

我只有有限的时间发布这个,但希望这个想法很明确。这是qsort可以设置的一种方式来做你正在寻找的东西。这是一个2D数组Nx3,我用[0.0,500]的随机值填充。这个想法可以扩展到3D和超越阵列。

诀窍是让行宽正确(或者在3D的情况下是平板,4D是立方体等等)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

int cmp_row(const void* arg1, const void* arg2)
{
    const double *ar1 = arg1;
    const double *ar2 = arg2;

    double diff = (ar1[1] + ar1[2] - ar2[1] - ar2[2]);
    return (diff < 0.0) ? -1 : (0.0 < diff);
}

int main(int argc, char *argv[])
{
    static const int N = 50;
    double (*ar)[3] = NULL;
    int i=0;

    // see prng
    srand((unsigned)time(NULL));

    // allocat space for Nx3 2D array.
    ar = calloc(N, sizeof(*ar));

    // since I've no test data, random fill with values
    //  from [0..500)
    for (i=0;i<N;++i)
    {
        ar[i][1] = ((double)rand()/(double)RAND_MAX)*500.0;
        ar[i][2] = ((double)rand()/(double)RAND_MAX)*500.0;
    }

    // sort by elements 1+2
    qsort(ar, N, sizeof(*ar), cmp_row);

    for (i=0;i<N;++i)
    {
        printf("%3d : %7.3f + %7.3f  = %7.3f\n",
               i+1, ar[i][1], ar[i][2], ar[i][1]+ar[i][2]);
    }

    // release allocation
    free(ar);

    return 0;
}

注意:在处理我所谓的仅语法2D +数组时,这会变得有点复杂。那些将是“数组”实际上是指针的向量。 int **ar等等。然而,前提几乎相同,只有比较器必须改变。如果我有时间,我会添加这样的野兽作为额外的样本,如果输入保证。

最后注意:这不能防止浮点值的潜在上溢或下溢。一个相当复杂的布尔逻辑的比较器可以做到这一点,但除非你的数据对这种极端情况敏感,否则这个例子几乎不值得。

输出(显然你的情况会有所不同)

我已经将ar[i][1] + ar[i][2]的总和作为排序顺序的证据,做了我认为你想要的事情。我希望这会有所帮助。

  1 :  47.986 +   1.471  =  49.457
  2 : 114.418 +  26.848  = 141.267
  3 : 148.183 +  12.145  = 160.328
  4 :  46.925 + 161.231  = 208.155
  5 : 102.405 + 116.097  = 218.502
  6 :  58.676 + 172.490  = 231.167
  7 : 144.797 +  99.977  = 244.774
  8 :   8.914 + 314.920  = 323.833
  9 :  68.885 + 255.924  = 324.809
 10 : 107.825 + 220.631  = 328.457
 11 : 287.056 +  44.610  = 331.665
 12 : 217.505 + 114.799  = 332.304
 13 : 240.620 + 104.506  = 345.127
 14 : 242.288 + 133.509  = 375.797
 15 : 381.538 +   4.073  = 385.611
 16 :   4.991 + 383.519  = 388.510
 17 : 257.611 + 163.872  = 421.483
 18 :  43.278 + 380.951  = 424.230
 19 : 300.775 + 129.879  = 430.654
 20 : 134.814 + 314.688  = 449.502
 21 : 103.281 + 346.874  = 450.155
 22 : 197.761 + 263.668  = 461.429
 23 : 303.872 + 173.430  = 477.302
 24 : 466.265 +  11.400  = 477.665
 25 : 108.817 + 391.995  = 500.812
 26 : 467.992 +  40.985  = 508.977
 27 : 353.493 + 160.398  = 513.891
 28 : 406.446 + 130.214  = 536.659
 29 : 244.678 + 303.989  = 548.667
 30 : 303.282 + 260.434  = 563.716
 31 : 254.139 + 317.150  = 571.290
 32 : 368.311 + 203.118  = 571.429
 33 : 372.654 + 201.597  = 574.251
 34 : 143.985 + 454.796  = 598.781
 35 : 254.561 + 402.038  = 656.598
 36 : 309.922 + 363.872  = 673.795
 37 : 196.554 + 478.447  = 675.000
 38 : 493.585 + 185.749  = 679.334
 39 : 438.196 + 257.858  = 696.054
 40 : 347.198 + 360.908  = 708.107
 41 : 262.210 + 456.034  = 718.244
 42 : 389.174 + 339.315  = 728.489
 43 : 300.199 + 446.422  = 746.621
 44 : 344.346 + 427.167  = 771.513
 45 : 317.604 + 470.313  = 787.917
 46 : 312.785 + 475.855  = 788.640
 47 : 334.682 + 492.928  = 827.609
 48 : 399.056 + 430.449  = 829.505
 49 : 460.128 + 373.025  = 833.154
 50 : 419.137 + 440.745  = 859.882