Funzione di libreria C per eseguire l'ordinamento


97

Esiste una funzione di libreria disponibile nella libreria standard C per eseguire l'ordinamento?


21
@Alexandru, il punto centrale di SO è essere un luogo per tutte le domande relative alla programmazione, di qualsiasi livello di abilità. Dove pensi che Google dovrebbe indirizzare le persone quando usano quella tua query? I poteri forti vogliono che venga qui : quando SO è il primo link di Google per quella query, il nostro lavoro è finito.
paxdiablo

1
Il mio codice originale era pigro e probabilmente molto diverso da quello che avresti trovato con una ricerca su Google. Tuttavia, dopo tutto l'input della comunità, hai un esempio di una buona implementazione di come usare qsort.
riesegui il

@paxdiablo: se è così, potrebbero anche ospitare semplicemente la documentazione di lib standard - dubito che questa domanda aggiungerà qualcosa al di sopra di quel riferimento canonico, qui. Per alcuni casi complessi, forse, ma solo per trovare una funzione di base?
Eamon Nerbonne

4
Anche domande come questa contribuiscono all'eventuale completezza di SO come database utile per programmatori bloccati.
thomaspaulb

7
Inoltre in molti casi le persone non sanno cosa cercare. Se sai che c ha una funzione di ordinamento chiamata qsort () la documentazione è facilmente accessibile, tuttavia se non sai cosa cercare quale risorsa dovresti usare.
replica il

Risposte:


120

qsort()è la funzione che stai cercando. Lo chiami con un puntatore al tuo array di dati, il numero di elementi in quell'array, la dimensione di ogni elemento e una funzione di confronto.

Fa la sua magia e il tuo array viene ordinato sul posto. Segue un esempio:

#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
Dovresti davvero usare sizeof (* x) nel caso in cui cambierai il tipo in futuro, ma +1 per fornire un campione.
paxdiablo

12
In generale, un tentativo di confrontare gli int sottraendoli uno dall'altro provocherà un overflow. È meglio stare lontano da quella cattiva abitudine fin dall'inizio. Usareturn (f > s) - (f < s);
AnT

4
Ok, modificato secondo la maggior parte dei suggerimenti. Traccio la linea, @ChrisL, a bisogno di size_t dato che i miei array non diventano mai così grandi :-) E, @AndreyT, per quanto intelligente sia questo trucco, preferisco che il mio codice sia leggibile :-)
paxdiablo

2
@paxdiablo: Quel "hack" è un idioma consolidato. Qualsiasi programmatore degno di questo nome lo riconosce immediatamente. Non ha effetti negativi sulla leggibilità.
AnT

2
@JAamish ISO C99 Standard N1256, in "7.20.5.2 La qsortfunzione" Punto 4 "Se due elementi sono uguali, il loro ordine nell'array ordinato risultante non è specificato."
12431234123412341234123

60

La libreria standard C / C ++ <stdlib.h>contiene la qsortfunzione.

Questa non è la migliore implementazione di ordinamento rapido al mondo, ma è abbastanza veloce e MOLTO FACILE da usare ... la sintassi formale di qsort è:

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

L'unica cosa che devi implementare è la funzione compare_, che accetta due argomenti di tipo "const void", che possono essere convertiti nella struttura dati appropriata, e quindi restituisce uno di questi tre valori:

  • negativo, se a dovrebbe essere prima di b
  • 0, se uguale a b
  • positivo, se a dovrebbe essere dopo b

1. Confronto di un elenco di numeri interi :

semplicemente gettare e b di interi se x < y, x-yè negativo, x == y, x-y = 0, x > y, x-yè positivo x-yè una scorciatoia per farlo :) inversa *x - *ya *y - *xper ordinare discendente / ordine inverso

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

2. Confronto di un elenco di stringhe :

Per confrontare la stringa, è necessaria la strcmpfunzione all'interno di <string.h>lib. strcmpper impostazione predefinita restituirà -ve, 0, ve in modo appropriato ... per ordinare in ordine inverso, basta invertire il segno restituito da strcmp

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

3. Confronto dei numeri in virgola mobile :

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. Confronto dei record in base a una chiave :

A volte è necessario ordinare elementi più complessi, come un record. Ecco il modo più semplice per farlo usando la qsortlibreria.

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
Una risposta abbastanza buona, ma la spiegazione del valore di ritorno della funzione di confronto è all'indietro. Inoltre, in alcuni esempi, stai eseguendo il trucco xy, che può dare risultati errati (ed è meno ovvio di un semplice confronto).
Adrian McCarthy,

Beh, per quanto mi riguarda ora .. funziona per ogni concorso;)
whacko__Cracko

5
Il trucco xy non funziona se la differenza tra x e y è maggiore del massimo int rappresentabile. Quindi va bene quando si confrontano due numeri positivi, ma fallirà il confronto, ad esempio, INT_MAX e -10. Voto positivo però perché mi piacciono tutti gli esempi di ordinamento di tipi molto diversi.
Douglas

2
Oltre al problema di overflow sia nel comparatore di numeri interi che nelle funzioni di confronto delle chiavi, la funzione di confronto delle stringhe non è corretta. Quando si ordina un array di int, i valori passati al comparatore sono entrambi int *mascherati da void *. Quando si ordina un array di char *, quindi, i valori passati al comparatore sono entrambi char **mascherati da void *. Pertanto, il codice corretto deve essere: int compare_function(const void *a,const void *b) { return (strcmp(*(char **)a, *(char **)b)); }.
Jonathan Leffler

1
Per confronti di numeri interi resistenti all'overflow, prendi in considerazione if (x > y) return +1; else if (x < y) return -1; else return 0;o, se desideri un'espressione semplice, allora return (x > y) - (x < y);. Questo valuta sempre due confronti a livello C, ma l'ottimizzatore potrebbe essere in grado di evitarlo. La sottrazione non funziona sui valori senza segno. La prima versione funziona bene quando si ha a che fare con una serie di confronti - confrontando prima 2 membri interi di una struttura, e se sono uguali, poi due doppi, poi due stringhe, ecc. C'è più di un modo per farlo, in C così come Perl.
Jonathan Leffler


6

Sebbene non sia esattamente nella libreria standard, https://github.com/swenson/sort ha solo due file di intestazione che puoi includere per ottenere l'accesso a una vasta gamma di instradamenti di ordinamento incredibilmente veloci, in questo modo:

#define SORT_NAME int64 #define SORT_TYPE int64_t #define SORT_CMP ( x , y ) (( x ) - ( y )) #include "sort.h" / * Ora hai accesso a int64_quick_sort, int64_tim_sort, ecc., ad esempio * / 
int64_quick_sort ( arr , 128 ); / * Presuppone che tu abbia int * arr o int arr [128]; * /

   
 
  

Dovrebbe essere almeno due volte più veloce della libreria standard qsort, poiché non usa puntatori a funzione e ha molte altre opzioni di algoritmo di ordinamento tra cui scegliere.

È in C89, quindi dovrebbe funzionare praticamente in ogni compilatore C.



4

Usa qsort()in <stdlib.h>.

@paxdiablo La qsort()funzione è conforme a ISO / IEC 9899: 1990 (`` ISO C90 '').


3

Sono disponibili diverse funzioni di ordinamento in C in stdlib.h. Puoi fare man 3 qsortsu una macchina unix per ottenere un elenco di loro ma includono:

  • heapsort
  • quicksort
  • mergesort

7
heapsort e mergesort non sono nello standard.
Technowise

3
Nemmeno il quicksort. Lo standard non stabilisce quale algoritmo viene utilizzato.
paxdiablo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.