Función de biblioteca C para realizar ordenación

97

¿Hay alguna función de biblioteca disponible en la biblioteca estándar de C para ordenar?

Ankur
fuente
21
@Alexandru, el objetivo de SO es ser un lugar para todas las preguntas relacionadas con la programación, de cualquier nivel de habilidad. ¿A dónde crees que debería dirigir Google a las personas cuando utilizan esa consulta tuya? Los poderosos quieren que venga aquí : cuando SO es el enlace principal de Google para esa consulta, nuestro trabajo está hecho.
paxdiablo
1
Mi código original era flojo y probablemente muy diferente de lo que hubiera encontrado con una búsqueda en Google. Sin embargo, después de todos los comentarios de la comunidad, tiene un ejemplo de una buena implementación de cómo usar qsort.
repetición el
@paxdiablo: si ese es el caso, también podrían simplemente alojar la documentación estándar de la biblioteca; dudo que esta pregunta agregue algo por encima de la referencia canónica, aquí. Para algunos casos complejos, quizás, pero ¿solo para encontrar una función básica?
Eamon Nerbonne
4
Incluso preguntas como esta contribuyen a la eventual integridad de SO como una base de datos útil para codificadores atascados.
thomaspaulb
7
Además, en muchos casos la gente no sabe qué buscar. Si sabe que c tiene una función de ordenación llamada qsort (), la documentación es de fácil acceso, sin embargo, si no sabe qué buscar, qué recurso debe usar.
repetición el

Respuestas:

120

qsort()es la función que estás buscando. Lo llama con un puntero a su matriz de datos, el número de elementos en esa matriz, el tamaño de cada elemento y una función de comparación.

Hace su magia y su matriz se ordena en el lugar. A continuación se muestra un ejemplo:

#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;
}
repetición
fuente
3
Realmente debería usar sizeof (* x) en caso de que alguna vez cambie el tipo en el futuro, pero +1 para proporcionar una muestra.
paxdiablo
12
En el caso general, un intento de comparar entradas restando una de otra resultará en un desbordamiento. Es mejor alejarse de ese mal hábito desde el principio. Usereturn (f > s) - (f < s);
LAn
4
Bien, cambiado según la mayoría de las sugerencias. Dibujo la línea, @ChrisL, en la necesidad de size_t ya que mis matrices nunca llegan a ser tan grandes :-) Y, @AndreyT, aunque ese truco es inteligente, prefiero que mi código sea legible :-)
paxdiablo
2
@paxdiablo: Ese "truco" es un modismo bien establecido. Cualquier programador que se precie lo reconoce de inmediato. No tiene efectos negativos en la legibilidad.
el AnT
2
@JAamish ISO C99 Norma N1256, en "7.20.5.2 La qsortfunción" Punto 4 "Si dos elementos se comparan como iguales, su orden en la matriz ordenada resultante no se especifica."
12431234123412341234123
60

La biblioteca estándar de C / C ++ <stdlib.h>contiene qsortfunción.

Esta no es la mejor implementación de ordenación rápida del mundo, pero es lo suficientemente rápida y MUY FÁCIL de usar ... la sintaxis formal de qsort es:

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

Lo único que necesita implementar es la función compare_function, que toma dos argumentos de tipo "const void", que se pueden convertir a la estructura de datos adecuada y luego devolver uno de estos tres valores:

  • negativo, si a debe ser antes de b
  • 0, si a es igual ab
  • positivo, si a debería ser después de b

1. Comparando una lista de números enteros :

simplemente echar a y b números enteros si x < y, x-yes negativo, x == y, x-y = 0, x > y, x-yes positivo x-yes una forma de acceso directo para hacerlo :) revertir *x - *ya *y - *xpara la clasificación en la disminución / orden inverso

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

2. Comparación de una lista de cadenas :

Para comparar cadenas, necesita una strcmpfunción dentro de <string.h>lib. strcmppor defecto devolverá -ve, 0, ve apropiadamente ... para ordenar en orden inverso, simplemente invierta el signo devuelto por strcmp

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

3. Comparación de números de coma flotante :

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. Comparación de registros basados ​​en una clave :

A veces necesita ordenar cosas más complejas, como grabar. Esta es la forma más sencilla de hacerlo utilizando la qsortbiblioteca.

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
fuente
2
Una respuesta bastante buena, pero la explicación del valor de retorno de la función de comparación es al revés. Además, en algunos de los ejemplos, está haciendo el truco xy, que puede dar resultados erróneos (y es menos obvio que una simple comparación).
Adrian McCarthy
Bueno, en lo que a mí respecta ahora ... esto funciona para todos los concursos;)
whacko__Cracko
5
El truco xy no funciona si la diferencia entre xey es mayor que el int representable más grande. Por lo tanto, está bien cuando se comparan dos números positivos, pero fallará al comparar, por ejemplo, INT_MAX y -10. Sin embargo, voté a favor porque me gustan todos los ejemplos de clasificación de tipos muy diferentes.
Douglas
2
Además del problema de desbordamiento tanto en el comparador de enteros como en el comparador de teclas, la función de comparación de cadenas es incorrecta. Al ordenar una matriz de int, los valores pasados ​​al comparador se int *disfrazan como void *. char *Por lo tanto, al ordenar una matriz de , los valores pasados ​​al comparador se char **disfrazan como void *. Por lo tanto, el código correcto debe ser: int compare_function(const void *a,const void *b) { return (strcmp(*(char **)a, *(char **)b)); }.
Jonathan Leffler
1
Para las comparaciones de enteros resistentes al desbordamiento, considere if (x > y) return +1; else if (x < y) return -1; else return 0;, o si desea una expresión simple, entonces return (x > y) - (x < y);. Esto siempre evalúa dos comparaciones en el nivel C, pero el optimizador podría evitarlo. La resta no funciona con valores sin firmar. La primera versión funciona bien cuando se trata de una serie de comparaciones: primero se comparan 2 miembros enteros de una estructura, y si son iguales, luego dos dobles, luego dos cadenas, etc. Hay más de una forma de hacerlo, en C y Perl.
Jonathan Leffler
9

Seguro: qsort()es una implementación de cierto tipo (no necesariamente una clasificación rápida como su nombre sugiere).

Pruebe man 3 qsort o lea en http://linux.die.net/man/3/qsort

McPherrinM
fuente
7
qsortno tiene que implementarse con Quicksort.
James McNellis
6

Si bien no está exactamente en la biblioteca estándar, https://github.com/swenson/sort tiene solo dos archivos de encabezado que puede incluir para obtener acceso a una amplia gama de enrutamientos de clasificación increíblemente rápidos, así:

#define SORT_NAME int64 #define SORT_TYPE int64_t #define SORT_CMP ( x , y ) (( x

  ) - ( y )) #include "sort.h" / * Ahora tiene acceso a int64_quick_sort, int64_tim_sort, etc., por ejemplo, * / 
int64_quick_sort ( arreglo , 128 ); / * Asume que tienes int * arr o int arr [128]; * /  
 
  

Esto debería ser al menos dos veces más rápido que la biblioteca estándar qsort, ya que no usa punteros de función y tiene muchas otras opciones de algoritmos de clasificación para elegir.

Está en C89, por lo que debería funcionar básicamente en todos los compiladores de C.

Christopher Swenson
fuente
4

prueba qsorten stdlib.h.

Chico tecnológico viajero
fuente
4

Usar qsort()en<stdlib.h> .

@paxdiablo La qsort()función cumple con ISO / IEC 9899: 1990 (`` ISO C90 '').

número primo
fuente
3

Hay varias funciones de clasificación C disponibles en stdlib.h. Puede hacerlo man 3 qsorten una máquina Unix para obtener una lista de ellos, pero incluyen:

  • montón
  • ordenación rápida
  • mergesort
dj2
fuente
7
heapsort y mergesort no están en el estándar.
Technowise
3
Tampoco es quicksort. El estándar no exige qué algoritmo se utiliza.
paxdiablo