在c中排序结构数组

时间:2010-11-22 12:49:11

标签: c sorting mergesort

我有一个结构:

  typedef struct book{
  double rating;
  double price;
  double relevance;
  int ID;
}B;

数组

list* B;

以及使用此

的文件中读取的文件
int read_file(char* infile, int N)
{
  int c;
  if((fp=fopen(infile, "rb")))
    {
      fscanf(fp, "%*s\t%*s\t%*s\t%*s\n");
      c=0;
      while((!feof(fp))&&(c<N))
    {
      fscanf(fp, "%lf\t%lf\t%lf\t%d\n", &list[c].rating,  &list[c].price, &list[c].relevance, &list[c].ID);   
      c++;
    }

 fclose(fp);      
    }
  else
    {
      fprintf(stderr,"%s did not open. Exiting.\n",infile);
      exit(-1);
    }
  return(c);
}

和比较方法

int comp_on_price(const void *a, const void *b)
{

  if ((*(B *)a).price < (*(B *)b).price)
    return 1;
  else if ((*(B *)a).price > (*(B *)b).price)
    return -1;
  else
    return 0;  

}

我想用nlog(n)时间进行稳定排序 也许按最低prie到最高的顺序合并排序

我只需要20个最低价格。

我将如何使用我的方法比较来实现这一点?

谢谢

7 个答案:

答案 0 :(得分:1)

  

我想用nlog(n)时间进行稳定排序,或者按最低prie到最高顺序合并排序

     

我只需要20个最低价格。

然后你可以在O(n)时间内完成这项工作。您可以在O(N)时间内找到前20个值,然后对那些O(1)进行排序。

See here for the STL C++ library version

Annotated Python implementation here

答案 1 :(得分:0)

qsort是你的朋友:)。 (虽然在最坏的情况下不是Nlog(N),但是做任何事情都很困难)

答案 2 :(得分:0)

您要使用的功能是qsort。 C带有一个完全可以接受的排序,完全你似乎需要的东西。

qsort本身不是一个稳定的排序(好吧,可能用于给定的实现,但标准并不保证它)但是它可以与一些诡计。之前我已经通过添加一个指向数组元素的指针来实现这一点,该数组元素最初填充了元素本身的地址(或者读取文件时可能会增加整数值)。

然后您可以将其用作次要密钥,以确保具有相同主键的元素保持有序。

如果想要改变结构,那么Algorithmist是get code的好地方。我自己,我倾向于对重新实现进行微小的修改。

要实际使其稳定,请将结构更改为:

typedef struct book {
  double rating;
  double price;
  double relevance;
  int ID;
  int seq;                                 // Added to store sequence number.
} B;

并将您的文件阅读代码更改为:

fscanf(fp, "%lf\t%lf\t%lf\t%d\n", ... 
list[c].seq = c;                           // Yes, just add this line.
c++;

然后您的比较功能变为:

int comp_on_price(const void *a, const void *b) {
    B *aa = (B*)a;
    B *bb = (B*)b;

    if (aa->price < bb->price)
        return 1;
    if (aa->price > bb->price)
        return -1;
    return (aa->seq < bb->seq) ? 1 : -1;   // Cannot compare equal.
}

答案 3 :(得分:0)

既然你提到了C而不是C ++,我会说你考虑实现类似于qsort()的自己版本。

看看如何定义qsort的比较器。您需要为自己定义类似的东西吗?对于实际排序,您需要从头开始实现自己的StableSort()版本。

答案 4 :(得分:0)

只是对比较函数稍作修改才能使库qsort稳定。请参见链接here

下面的内容应该可以解决问题(未经测试,要小心):

int comp_on_price(const void *a, const void *b)
{
    if ((*(B *)a).price < (*(B *)b).price)
        return 1;
    else if ((*(B *)a).price > (*(B *)b).price)
        return -1;
    else
        // if zero order by addresses
        return a-b;
}

如果你可以保证a和b在相同的地址空间(同一个数组中的两个指针)并且每个比较都给出了更大的数组整体排序,那么这将有效,较低结构的地址将变得更慢。泡沫种类或类似情况也是如此。这也适用于QucikSort的微不足道的实现(qsort不是)。但是对于其他算法或任何使用额外地址空间进行临时存储的算法(可能用于优化目的),此属性将不成立。

如果您排序的内容包含比较项目中的任何唯一标识符(在当前示例中,对于字段ID可能是真的),另一种使排序稳定的方法是比较这些项目。您也可以为此目的在新字段中添加这样一个唯一键,但由于它使用更多内存,因此在执行此操作之前应考虑下面描述的第三个选项。

我首选的方法仍然是第三种方法,不要直接对结构数组进行排序,而是对指向实际结构项的指针数组进行排序。这有几个很好的属性。首先,您可以比较指向的结构数组,因为它不会改变,它将使排序稳定。

比较功能将变为:

int comp_on_price(const void *a, const void *b)
{
    if ((*(B **)a)->price < (*(B **)b)->price)
        return 1;
    else if ((*(B **)a)->price > (*(B **)b)->price)
        return -1;
    else
        // if zero, order by addresses
        return *(B **)a-*(B **)b;
}

其他好的属性是它避免在排序时移动结构,它只需要移动指针,这可以节省时间。您还可以保留多个这样的指针数组,并允许同时对数组项进行多次有序访问。

缺点是需要一些内存,而且对项目的访问速度稍慢(一个间接更多级别)。

答案 5 :(得分:0)

你不需要qsort一切。只需为20个最低记录创建一个空的B *数组,复制第一个&lt; = 20个记录,然后对它们进行qsort,如果有超过20个,那么当你迭代你的元素时,将它们与前20个中的最高值进行比较:如果更多然后继续比较下一个最高等等回到最低然后移动其他指针为下一个条目在低20中腾出空间。你确实需要一个确定性的比较 - 在​​那个方面听paxdiablo:添加输入记录号或其他东西来区分记录。

答案 6 :(得分:-1)

我终于使用计数排序做了这个,它在c中占用了超过100行代码。

然后我在shell脚本中的一行中完成了它

sort -nk 2,2 -s Wodehouse.txt | sort -rnk 3,3 -s | sort -rnk 1,1 -s | head -20