Função da biblioteca C para realizar a classificação

97

Existe alguma função de biblioteca disponível na biblioteca padrão C para fazer a classificação?

Ankur
fonte
21
@Alexandru, o objetivo do SO é ser um lugar para todas as questões relacionadas à programação, de qualquer nível de habilidade. Para onde você acha que o Google deve direcionar as pessoas quando elas usarem essa sua consulta? As autoridades querem que ele chegue aqui - quando SO é o principal link do Google para essa consulta, nosso trabalho está feito.
paxdiablo
1
Meu código original era preguiçoso e provavelmente muito diferente do que você teria encontrado com uma pesquisa no Google. No entanto, após todas as contribuições da comunidade, você tem um exemplo de uma boa implementação de como usar o qsort.
executado novamente em
@paxdiablo: se for esse o caso, eles podem simplesmente hospedar a documentação lib padrão - eu duvido que esta pergunta adicione algo acima da referência canônica, aqui. Para alguns casos complexos, talvez - mas apenas para encontrar uma função básica?
Eamon Nerbonne
4
Mesmo questões como essa contribuem para a eventual integridade do SO como um banco de dados útil para codificadores travados.
thomaspaulb
7
Além disso, em muitos casos, as pessoas não sabem o que pesquisar. Se você sabe que c tem uma função de classificação chamada qsort (), a documentação é facilmente acessível, no entanto, se você não sabe o que procurar, qual recurso deve ser usado.
repetido em

Respostas:

120

qsort()é a função que você está procurando. Você o chama com um ponteiro para seu array de dados, o número de elementos nesse array, o tamanho de cada elemento e uma função de comparação.

Ele faz sua mágica e seu array é classificado no local. Segue um exemplo:

#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;
}
repetir
fonte
3
Você realmente deve usar sizeof (* x) no caso de mudar o tipo no futuro, mas +1 para fornecer uma amostra.
paxdiablo
12
No caso geral, uma tentativa de comparar ints subtraindo um do outro resultará em estouro. É melhor ficar longe desse mau hábito desde o início. Usoreturn (f > s) - (f < s);
ANT
4
Ok, alterado de acordo com a maioria das sugestões. Eu traço o limite, @ChrisL, de precisar de size_t já que meus arrays nunca ficam tão grandes :-) E, @AndreyT, por mais inteligente que seja esse hack, prefiro que meu código seja legível :-)
paxdiablo
2
@paxdiablo: Esse "hack" é um idioma bem estabelecido. Qualquer programador que se preze o reconhece imediatamente. Não tem efeitos negativos na legibilidade.
AnT
2
@JAamish ISO C99 Padrão N1256, em "7.20.5.2 A qsortfunção" Ponto 4 "Se dois elementos são comparados como iguais, sua ordem na matriz classificada resultante não é especificada."
12431234123412341234123
60

A biblioteca padrão C / C ++ <stdlib.h>contém qsortfunções.

Esta não é a melhor implementação de classificação rápida do mundo, mas é rápida e MUITO FÁCIL de ser usada ... a sintaxe formal do qsort é:

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

A única coisa que você precisa implementar é compare_function, que recebe dois argumentos do tipo "const void", que podem ser convertidos para a estrutura de dados apropriada e, em seguida, retorna um destes três valores:

  • negativo, se a deve ser antes de b
  • 0, se a igual a b
  • positivo, se a deve ser após b

1. Comparando uma lista de inteiros :

simplesmente fundido a e b para se inteiros x < y, x-yé negativo, x == y, x-y = 0, x > y, x-yé positiva x-yé uma forma de atalho para fazê-lo :) reverter *x - *ypara *y - *xpor ordem decrescente / ordem inversa

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

2. Comparando uma lista de strings :

Para comparar strings, você precisa de uma strcmpfunção dentro de <string.h>lib. strcmpirá, por padrão, retornar -ve, 0, ve apropriadamente ... para classificar na ordem reversa, apenas inverta o sinal retornado por strcmp

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

3. Comparando números de ponto flutuante :

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. Comparando registros com base em uma chave :

Às vezes você precisa classificar coisas mais complexas, como o registro. Aqui está a maneira mais simples de fazer isso usando a 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
fonte
2
Uma resposta muito boa, mas a explicação do valor de retorno da função de comparação está ao contrário. Além disso, em alguns dos exemplos, você está fazendo o truque xy, que pode dar resultados errados (e é menos óbvio do que uma simples comparação).
Adrian McCarthy
Bem, no que me diz respeito agora ... isso funciona para todos os concursos;)
whacko__Cracko
5
O truque xy não funciona se a diferença entre xey for maior do que o maior int representável. Portanto, não há problema em comparar dois números positivos, mas falhará na comparação, por exemplo, INT_MAX e -10. Votado porque gosto de todos os exemplos de classificação de tipos muito diferentes.
Douglas
2
Assim como o problema de estouro tanto no comparador inteiro quanto nas funções do comparador chave, a função de comparação de string está incorreta. Ao classificar uma matriz de int, os valores passados ​​para o comparador são int *disfarçados como void *. Ao classificar uma matriz de char *, portanto, os valores passados ​​para o comparador são char **disfarçados como void *. Portanto, o código correto deve ser: int compare_function(const void *a,const void *b) { return (strcmp(*(char **)a, *(char **)b)); }.
Jonathan Leffler
1
Para comparações de inteiros que são resistentes a estouro, considere if (x > y) return +1; else if (x < y) return -1; else return 0;, ou se você quiser uma expressão simples, então return (x > y) - (x < y);. Isso sempre avalia duas comparações no nível C, mas o otimizador pode ser capaz de evitar isso. A subtração não funciona em valores sem sinal. A primeira versão funciona bem quando você está lidando com uma série de comparação - comparando 2 membros inteiros de uma estrutura primeiro, e se eles forem iguais, então dois duplos, depois duas strings, etc. Há mais de uma maneira de fazer isso, em C, bem como em Perl.
Jonathan Leffler
9

Com certeza: qsort()é uma implementação de um tipo (não necessariamente quicksort como seu nome pode sugerir).

Tente man 3 qsort ou leia em http://linux.die.net/man/3/qsort

McPherrinM
fonte
7
qsortnão precisa ser implementado usando Quicksort.
James McNellis
6

Embora não esteja exatamente na biblioteca padrão, https://github.com/swenson/sort tem apenas dois arquivos de cabeçalho que você pode incluir para obter acesso a uma ampla variedade de roteamentos de classificação incrivelmente rápidos, como:

#define SORT_NAME int64 #define SORT_TYPE int64_t #define SORT_CMP ( x , y ) (( x ) - ( y )) #include "sort.h" / * Agora você tem acesso a int64_quick_sort, int64_tim_sort, etc., por exemplo, * / 
int64_quick_sort ( arr , 128 ); / * Presume que você tenha algum int * arr ou int arr [128]; * /

   
 
  

Isso deve ser pelo menos duas vezes mais rápido que a biblioteca padrão qsort, já que não usa ponteiros de função e tem muitas outras opções de algoritmo de classificação para escolher.

Está no C89, então deve funcionar basicamente em todos os compiladores C.

Christopher Swenson
fonte
4

tente qsortem stdlib.h.

Viajando Tech Guy
fonte
4

Use qsort()em <stdlib.h>.

@paxdiablo A qsort()função está de acordo com a ISO / IEC 9899: 1990 (`` ISO C90 '').

número primo
fonte
3

Existem várias funções de classificação C disponíveis em stdlib.h. Você pode fazer man 3 qsortem uma máquina Unix para obter uma lista deles, mas eles incluem:

  • heapsort
  • ordenação rápida
  • mergesort
dj2
fonte
7
heapsort e mergesort não estão no padrão.
Technowise
3
Nem é quicksort. O padrão não determina qual algoritmo é usado.
paxdiablo