Fonction de bibliothèque C pour effectuer le tri

98

Existe-t-il une fonction de bibliothèque disponible dans la bibliothèque standard C pour effectuer le tri?

Ankur
la source
21
@Alexandru, tout l'intérêt de SO est d'être un lieu pour toutes les questions liées à la programmation, quel que soit le niveau de compétence. Selon vous, vers où Google devrait-il diriger les internautes lorsqu'ils utilisent votre requête? Les pouvoirs en place veulent que cela vienne ici - lorsque SO est le principal lien Google pour cette requête, notre travail est terminé.
paxdiablo
1
Mon code d'origine était paresseux et probablement très différent de ce que vous auriez trouvé avec une recherche Google. Cependant, après toutes les contributions de la communauté, vous avez un exemple d'une bonne implémentation de la façon d'utiliser qsort.
rediffusion
@paxdiablo: si c'est le cas, ils pourraient tout aussi bien héberger simplement la documentation standard de la bibliothèque - je doute que cette question ajoute quelque chose au-dessus de cette référence canonique, ici. Pour certains cas complexes, peut-être - mais juste pour trouver une fonction de base?
Eamon Nerbonne
4
Même des questions comme celle-ci contribuent à l'exhaustivité éventuelle de SO en tant que base de données utile pour les codeurs bloqués.
littlegreen
7
De plus, dans de nombreux cas, les gens ne savent pas quoi rechercher. Si vous savez que c a une fonction de tri nommée qsort (), la documentation est facilement accessible, cependant si vous ne savez pas quoi chercher quelle ressource doit-on utiliser.
rediffusé le

Réponses:

120

qsort()est la fonction que vous recherchez. Vous l'appelez avec un pointeur vers votre tableau de données, le nombre d'éléments dans ce tableau, la taille de chaque élément et une fonction de comparaison.

Il fait sa magie et votre tableau est trié sur place. Un exemple suit:

#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;
}
rediffusion
la source
3
Vous devriez vraiment utiliser sizeof (* x) au cas où vous changeriez de type à l'avenir, mais +1 pour fournir un échantillon.
paxdiablo
12
Dans le cas général, une tentative de comparaison des entiers en soustrayant les uns des autres entraînera un débordement. Il vaut mieux éviter cette mauvaise habitude dès le début. Utilisationreturn (f > s) - (f < s);
Du
4
D'accord, modifié selon la plupart des suggestions. Je trace la ligne, @ChrisL, à avoir besoin de size_t puisque mes tableaux ne deviennent jamais aussi gros :-) Et, @AndreyT, bien que ce soit intelligent, je préfère que mon code soit lisible :-)
paxdiablo
2
@paxdiablo: Ce "hack" est un idiome bien établi. Tout programmeur digne de ce nom le reconnaît immédiatement. Il n'a aucun effet négatif sur la lisibilité.
Du
2
@JAamish ISO C99 Standard N1256, dans "7.20.5.2 La qsortfonction" Point 4 "Si deux éléments se comparent comme égaux, leur ordre dans le tableau trié résultant n'est pas spécifié."
12431234123412341234123
61

La bibliothèque standard C / C ++ <stdlib.h>contient une qsortfonction.

Ce n'est pas la meilleure implémentation de tri rapide au monde mais elle est assez rapide et TRÈS FACILE à utiliser ... la syntaxe formelle de qsort est:

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

La seule chose que vous devez implémenter est la fonction compare_function, qui prend deux arguments de type "const void", qui peuvent être convertis en une structure de données appropriée, puis renvoyer l'une de ces trois valeurs:

  • négatif, si a doit être avant b
  • 0, si a égal à b
  • positif, si a doit être après b

1. Comparaison d'une liste d'entiers :

simplement coulé a et b des nombres entiers de cas x < y, x-yest négative, x == y, x-y = 0, x > y, x-yest positif x-yest un moyen de raccourci pour le faire :) inverse *x - *yà *y - *xde tri décroissant / ordre inverse

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

2. Comparaison d'une liste de chaînes :

Pour comparer une chaîne, vous avez besoin d'une strcmpfonction dans <string.h>lib. strcmpretournera par défaut -ve, 0, ve de manière appropriée ... pour trier dans l'ordre inverse, inversez simplement le signe renvoyé par strcmp

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

3. Comparaison des nombres à virgule flottante :

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. Comparaison des enregistrements en fonction d'une clé :

Parfois, vous devez trier des éléments plus complexes, tels que des enregistrements. Voici le moyen le plus simple de le faire à l'aide de la qsortbibliothèque.

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;
}
whacko__Cracko
la source
2
Une assez bonne réponse, mais l'explication de la valeur de retour de la fonction de comparaison est à l'envers. De plus, dans certains exemples, vous faites le tour xy, qui peut donner des résultats erronés (et est moins évident qu'une simple comparaison).
Adrian McCarthy
Eh bien, en ce qui me concerne maintenant .. cela fonctionne pour tous les concours;)
whacko__Cracko
5
L'astuce xy ne fonctionne pas si la différence entre x et y est supérieure au plus grand entier représentable. Donc c'est bien quand on compare deux nombres positifs, mais cela échouera en comparant, par exemple, INT_MAX et -10. Bien voté car j'aime tous les exemples de tri de types très différents.
Douglas
2
En plus du problème de débordement dans le comparateur d'entiers et les fonctions de comparateur clé, la fonction de comparaison de chaînes est incorrecte. Lors du tri d'un tableau de int, les valeurs transmises au comparateur sont toutes deux int *déguisées en void *. Lors du tri d'un tableau de char *, par conséquent, les valeurs transmises au comparateur sont toutes deux char **déguisées en void *. Par conséquent, le bon code doit être: int compare_function(const void *a,const void *b) { return (strcmp(*(char **)a, *(char **)b)); }.
Jonathan Leffler
1
Pour les comparaisons d'entiers résistantes aux débordements, pensez à if (x > y) return +1; else if (x < y) return -1; else return 0;, ou si vous voulez une expression simple, alors return (x > y) - (x < y);. Cela évalue toujours deux comparaisons au niveau C, mais l'optimiseur pourrait peut-être éviter cela. La soustraction ne fonctionne pas sur les valeurs non signées. La première version fonctionne bien lorsque vous avez affaire à une série de comparaison - en comparant d'abord 2 membres entiers d'une structure, et s'ils sont égaux, alors deux doubles, puis deux chaînes, etc. Il y a plus d'une façon de le faire, en C ainsi qu'en Perl.
Jonathan Leffler
9

Bien sûr: qsort()est une implémentation d'une sorte (pas nécessairement de tri rapide comme son nom pourrait le suggérer).

Essayez man 3 qsort ou lisez-le sur http://linux.die.net/man/3/qsort

McPherrinM
la source
7
qsortne doit pas être implémenté à l'aide de Quicksort.
James McNellis
6

Bien que n'étant pas exactement dans la bibliothèque standard, https://github.com/swenson/sort ne contient que deux fichiers d'en-tête que vous pouvez inclure pour accéder à un large éventail de routages de tri incroyablement rapides, comme ceci:

#define SORT_NAME int64 #define SORT_TYPE int64_t #define SORT_CMP ( x , y ) (( x ) - ( y )) #include "sort.h" / * Vous avez maintenant accès à int64_quick_sort, int64_tim_sort, etc., par exemple * / 
int64_quick_sort ( arr , 128 ); / * Suppose que vous avez des int * arr ou int arr [128]; * /

   
 
  

Cela devrait être au moins deux fois plus rapide que la bibliothèque standard qsort, car elle n'utilise pas de pointeurs de fonction et propose de nombreuses autres options d'algorithme de tri.

Il est en C89, il devrait donc fonctionner dans pratiquement tous les compilateurs C.

Christopher Swenson
la source
4

essayez qsortdans stdlib.h.

Tech Guy itinérant
la source
4

Utiliser qsort()dans <stdlib.h>.

@paxdiablo La qsort()fonction est conforme à la norme ISO / CEI 9899: 1990 (`` ISO C90 '').

nombre premier
la source
3

Plusieurs fonctions de tri C sont disponibles dans stdlib.h . Vous pouvez faire man 3 qsortsur une machine unix pour en obtenir une liste, mais ils incluent:

  • tas de choses
  • tri rapide
  • tri par fusion
dj2
la source
7
heapsort et mergesort ne sont pas dans la norme.
Technowise
3
Le tri rapide non plus. La norme ne précise pas quel algorithme est utilisé.
paxdiablo