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.