C库函数执行排序


96

C标准库中是否有可用的库函数来进行排序?


21
@ Alexandru,SO的重点是要解决所有与编程有关的任何问题,无论其技能水平如何。您认为当人们使用您的查询时,Google应该将人们引导到哪里?这将需要它来的权力,在这里 -当SO是前谷歌链接进行查询,我们的工作就完成了。
paxdiablo

1
我的原始代码很懒,可能与您在Google搜索中找到的代码有很大不同。但是,在所有社区的投入之后,您将获得一个很好的示例,说明如何使用qsort。
重新运行

@paxdiablo:如果是这种情况,那么他们也可以只托管标准的lib文档-我怀疑这个问题会在此处添加超出规范引用的内容。对于某些复杂的情况,也许-只是为了找到基本功能?
Eamon Nerbonne 09年

4
甚至像这样的问题也会使SO最终成为完整的编码器,从而成为有用的数据库。
thomaspaulb

7
同样在许多情况下,人们也不知道要搜索什么。如果您知道c有一个名为qsort()的排序函数,那么可以很容易地访问文档,但是如果您不知道要查找的内容,那么应该使用哪种资源。
重新运行

Answers:


119

qsort()是您要寻找的功能。您可以使用指向数据数组的指针,该数组中元素的数量,每个元素的大小以及一个比较函数来调用它。

它发挥了魔力,并且您的数组已就地排序。下面是一个示例:

#include <stdio.h>
#include <stdlib.h>
int comp (const void * elem1, const void * elem2) 
{
    int f = *((int*)elem1);
    int s = *((int*)elem2);
    if (f > s) return  1;
    if (f < s) return -1;
    return 0;
}
int main(int argc, char* argv[]) 
{
    int x[] = {4,5,2,3,1,0,9,8,6,7};

    qsort (x, sizeof(x)/sizeof(*x), sizeof(*x), comp);

    for (int i = 0 ; i < 10 ; i++)
        printf ("%d ", x[i]);

    return 0;
}

3
您确实应该使用sizeof(* x),以防将来将来更改类型,但为提供样本而更改+1。
paxdiablo

12
在一般情况下,尝试通过从另一个中减去一个来比较int会导致溢出。最好从一开始就避免这种不良习惯。使用return (f > s) - (f < s);
AnT

4
好的,根据大多数建议进行了更改。我画线@ChrisL是需要size_t的,因为我的数组永远不会变得那么大:-)而且,@AndreyT,尽管很聪明,但我更希望代码易于阅读:-)
paxdiablo

2
@ paxdiablo:那个“ hack”是一个公认的习语。任何值得一试的程序员都会立即意识到这一点。它对可读性没有负面影响。
AnT

2
“ @JAamish ISO C99标准N1256,在” 7.20.5.2 qsort函数“中,第4点”如果两个元素比较相等,则它们在所得排序数组中的顺序未指定。“
12

60

C / C ++标准库<stdlib.h>包含qsort函数。

这不是世界上最好的快速排序实现,但是它足够快且非常容易使用... qsort的正式语法是:

qsort(<arrayname>,<size>,sizeof(<elementsize>),compare_function);

您唯一需要实现的是compare_function,它接受两个类型为“ const void”的参数,可以将其转换为适当的数据结构,然后返回这三个值之一:

  • 负数,如果a应该在b之前
  • 0,如果a等于b
  • 正,如果a应该在b之后

1.比较整数列表

可简单地把A和B,如果整数x < yx-y是消极的,x == yx-y = 0x > yx-y是积极 x-y的捷径办法做到这一点:)逆转*x - *y,以*y - *x在减少排序/逆序

int compare_function(const void *a,const void *b) {
int *x = (int *) a;
int *y = (int *) b;
return *x - *y;
}

2.比较字符串列表

为了比较字符串,您需要strcmp<string.h>lib 内部使用函数。 strcmp默认情况下将适当地返回-ve,0,ve ...以相反的顺序排序,只需反转strcmp返回的符号

#include <string.h>
int compare_function(const void *a,const void *b) {
return (strcmp((char *)a,(char *)b));
}

3.比较浮点数

int compare_function(const void *a,const void *b) {
double *x = (double *) a;
double *y = (double *) b;
// return *x - *y; // this is WRONG...
if (*x < *y) return -1;
else if (*x > *y) return 1; return 0;
}

4.根据一个键比较记录

有时您需要对更复杂的内容进行排序,例如记录。这是使用qsort库的最简单方法。

typedef struct {
int key;
double value;
} the_record;

int compare_function(const void *a,const void *b) {
the_record *x = (the_record *) a;
the_record *y = (the_record *) b;
return x->key - y->key;
}

2
一个很好的答案,但是对compare函数的返回值的解释是向后的。另外,在某些示例中,您正在执行xy技巧,这可能会导致错误的结果(并且不如简单的比较明显)。
Adrian McCarthy

好吧,就我现在而言..这适用于每场比赛;)
whacko__Cracko

5
如果x和y之差大于最大可表示的int,则xy技巧不起作用。因此,比较两个正数是可以的,但是比较失败,例如INT_MAX和-10。尽管受到支持,因为我喜欢所有排序非常不同类型的示例。
道格拉斯

2
以及整数比较器和键比较器函数中的溢出问题,字符串比较函数都是不正确的。对数组进行排序时int,传递给比较器的值都int *伪装为void *char *因此,在对数组进行排序时,传递给比较器的值都char **伪装成void *。因此,正确的代码需要为:int compare_function(const void *a,const void *b) { return (strcmp(*(char **)a, *(char **)b)); }
乔纳森·勒夫勒

1
对于耐溢出的整数比较,请考虑if (x > y) return +1; else if (x < y) return -1; else return 0;,或者如果您想要一个简单的表达式,则选择return (x > y) - (x < y);。这总是在C级别评估两个比较,但是优化程序可能会避免这种情况。减法不适用于无符号值。第一个版本在处理一系列比较时效果很好—首先比较结构的2个整数成员,如果相等,则比较两个双精度,然后比较两个字符串,等等。有多种方法可以实现,在C和Perl中。
乔纳森·勒夫勒


6

虽然不是完全在标准库中,但https://github.com/swenson/sort仅有两个头文件,您可以包括它们来访问各种令人难以置信的快速排序路由,例如:

#define SORT_NAME int64 #define SORT_TYPE int64_t #define SORT_CMP x y ((x - y ))#include “ sort.h” / *您现在可以访问int64_quick_sort,int64_tim_sort等,例如* / 
int64_quick_sort arr 128 ); / *假设您有一些int * arr或int arr [128]; * /

   
 
  

这应该至少是标准库的两倍qsort,因为它不使用函数指针,并且有许多其他排序算法选项可供选择。

它在C89中,因此基本上应该在每个C编译器中都可以工作。



4

qsort()在中使用<stdlib.h>

@paxdiablo该qsort()功能符合ISO / IEC 9899:1990(``ISO C90'')。


3

中提供了几种C排序功能stdlib.h。您可以man 3 qsort在unix机器上进行操作以获取它们的列表,但它们包括:

  • 堆排序
  • 快速排序
  • 合并排序

7
heapsort和mergesort不在标准中。
Technowise

3
都不是快速排序。该标准不强制使用哪种算法。
paxdiablo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.