简体   繁体   English

c中的结构排序数组

[英]sorting array of structs in c

i have a structure : 我有一个结构:

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

an array 数组

list* B;

and a file of these so read in the files with this 和这些的文件,所以用这个读入文件

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);
}

and a compare method 和比较方法

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;  

}

I would like a stable sort with nlog(n) time perhaps merge sort in order of lowest prie to highest 我想用nlog(n)时间进行稳定排序,也许以最低优先级到最高优先级的顺序合并排序

i only need the 20 lowest prices. 我只需要20个最低价格。

how would i implement this using my compare to method? 我将如何使用我的“比较”方法实现此目标?

thanks 谢谢

I would like a stable sort with nlog(n) time perhaps merge sort in order of lowest prie to highest 我想用nlog(n)时间进行稳定排序,也许以最低优先级到最高优先级的顺序合并排序

i only need the 20 lowest prices. 我只需要20个最低价格。

Then you can do this in O(n) time. 然后,您可以在O(n)时间内完成此操作。 You can find the first 20 values in O(N) time then sort those O(1). 您可以找到O(N)时间中的前20个值,然后对这些O(1)进行排序。

See here for the STL C++ library version 请参阅此处以获取STL C ++库版本

Annotated Python implementation here 带注释的Python实现

qsort is your friend :). qsort是你的朋友:)。 (while it's not Nlog(N) in worst case, it's difficult do do anything faster) (虽然在最坏的情况下它不是Nlog(N),但是做任何事情都很难更快)

The function you want to use is qsort . 您要使用的功能是qsort C comes with a perfectly acceptable sort which does exactly what you seem to need. C带有一个完全可以接受的排序,可以完全满足您的需求。

qsort itself isn't a stable sort (well, it may be for a given implementation, but the standard doesn't guarantee it) but it can be made into one with some trickery. qsort本身不是一个稳定的排序(嗯,它可能是给定的实现,但是标准不能保证它),但是可以将其组合成一个小技巧。 I've done that before by adding a pointer to the array elements which is initially populated with the address of the element itself (or an increasing integer value as you read the file will probably do here). 在添加指向数组元素的指针之前,我已经完成了此操作,该指针最初由元素本身的地址填充(或者在读取文件时增加整数值可能会在此处完成)。

Then you can use that as a minor key, which ensures elements with the same major key are kept in order. 然后,您可以将其用作次要键,以确保具有相同主键的元素保持顺序。

If you don't want to go to the trouble of changing the structures, Algorithmist is a good place to get code from. 如果你不想去改变结构的麻烦,Algorithmist是个好地方,以获取代码从。 Myself, I tend to prefer minor modifications to re-implementations. 我自己,我倾向于对重新实现进行较小的修改。

To actually make it stable, change your structure to: 要使其真正稳定,请将结构更改为:

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

and change your file reading code to: 并将文件读取代码更改为:

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

then your comparison function becomes something like: 那么您的比较函数将变为:

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.
}

Since you mentioned C and not C++, I would say you consider implementing your own version of something similar to qsort() . 因为您提到的是C而不是C ++,所以我想说您考虑实现自己的类似于qsort()的版本

Look at how the comparator for qsort is defined. 查看如何定义qsort的比较器。 You would need to define something similar for yourself? 您需要为自己定义类似的东西吗? For the actual sorting, you would need to implement your own version of StableSort() from scratch. 对于实际的排序,您需要从头开始实现自己的StableSort()版本。

It's just a slight changes to your comparizon function to make library qsort stable. 只是对comparizon函数进行了少许更改,以使库qsort稳定。 See link here 在这里查看链接

Something like below should do the trick (untested, be cautious): 像下面这样的事情应该可以解决(未经测试,请谨慎):

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;
}

This would work if you can guarantee a and b are in the same address space (two pointers in the same array) and that every comparisons give a greater overall ordering of the array, addresses of lower structures will tend to become even slower. 如果可以保证a和b在相同的地址空间(同一数组中的两个指针)并且每次比较都给出该数组的整体顺序较大,则较低结构的地址趋向于变得更慢,这将起作用。 This is true for bubble sorts or similar. 对于冒泡排序或类似情况,这是正确的。 That would also work for a trivial implementation of QucikSort (which qsort is not). 这对于QucikSort的简单实现(qsort不是)也很有效。 However for other algorithms, or any algorithm using additional address space for temporary storage (maybe for optimization purpose), this property will not be true. 但是,对于其他算法或使用额外地址空间进行临时存储(可能出于优化目的)的任何算法,此属性将不成立。

If what you sort contains any unique identifier in compared items (in the current example that is probably true for field ID), another method to make the sort stable would be to compare these items. 如果排序的内容在被比较项中包含任何唯一标识符(在当前示例中,字段ID可能正确),则使排序稳定的另一种方法是比较这些项。 You could also add such a unique key in a new field for that purpose, but as it uses more memory you should consider the third option described below before doing that. 您也可以为此目的在新字段中添加这样的唯一键,但是由于它使用更多的内存,因此在执行此操作之前,应考虑以下所述的第三个选项。

My preferred method would still be a third one, do not directly sort an array of structures, but sort an array of pointers to actual structure items. 我的首选方法仍然是第三个方法,不要直接对结构数组进行排序,而是对指向实际结构项的指针进行排序。 This has several good properties. 这具有几个良好的特性。 First you can compare arrays of the structure pointed to, as it won't change and it will make the sort stable. 首先,您可以比较所指向结构的数组,因为它不会改变,并且会使排序稳定。

The comparison function will become something like: 比较功能将变为:

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;
}

Other good properties is that it avoid moving structures around while sorting, it only need moving pointers, and that can be time saving. 其他好的特性是,它避免在排序时移动结构,只需要移动指针即可,这可以节省时间。 You can also keep several such pointer arrays, and that allow several ordered accesses to array items at the same time. 您还可以保留多个此类指针数组,并允许同时对数组项进行多个有序访问。

Drawbacks are that it takes some memory and that access to items is slightly slower (one level of indirection more). 缺点是它需要一些内存,并且对项目的访问稍微慢一些(一级间接访问更多)。

You don't need to qsort everything. 您无需对所有内容进行qsort。 Just create an empty B* array for the 20 lowest records, copy the first <=20 records in there and qsort them, if there are more than 20 then as you iterate over your elements compare them to the highest in the first 20: if more then continue else compare to next highest etc. back to the lowest then shift the other pointers to make space for your next entry in the low-20. 只需为最下面的20条记录创建一个空的B *数组,复制其中的前<= 20条记录并对其进行qsort,如果有20条以上,则在迭代元素时将它们与前20条中的最高记录进行比较:更多,然后继续,否则与下一个最高点进行比较,等等。返回到最低点,然后移动其他指针,为下一个进入低20位置留出空间。 You do need a deterministic comparison - listen to paxdiablo on that front: add an input record number or something to differentiate records. 您确实需要确定性的比较-听那边的paxdiablo:添加输入记录编号或其他可以区分记录的内容。

i finally did this using a counting sort it took over 100 lines of code in c. 我最终使用计数排序完成了此操作,在c语言中占用了100多行代码。

i then did it in one line in a shell script 然后我在shell脚本中一行完成了

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM