Quais são os casos de uso em que um algoritmo de classificação específico é preferido em relação a outros - classificação por mesclagem vs QuickSort vs heapsort vs 'classificação por introdução', etc?
Existe um guia recomendado para usá-los com base no tamanho, tipo de estrutura de dados, memória e cache disponíveis e desempenho da CPU?
Respostas:
Primeiro, uma definição, uma vez que é muito importante: uma classificação estável é aquela garantida para não reordenar elementos com chaves idênticas.
Recomendações:
Classificação rápida: quando você não precisa de uma classificação estável e o desempenho médio do caso importa mais do que o pior desempenho do caso. Uma classificação rápida é O (N log N) em média, O (N ^ 2) no pior caso. Uma boa implementação usa armazenamento auxiliar O (log N) na forma de espaço de pilha para recursão.
Classificação de mesclagem: quando você precisa de uma classificação O (N log N) estável, trata-se da sua única opção. A única desvantagem disso é que ele usa espaço auxiliar O (N) e tem uma constante um pouco maior que uma ordenação rápida. Existem algumas classificações de mesclagem no local, mas elas não são estáveis ou piores que O (N log N). Até as ordenações O (N log N) existentes têm uma constante muito maior que a ordenação antiga simples, que são mais curiosidades teóricas do que algoritmos úteis.
Classificação de pilha: quando você não precisa de uma classificação estável e se preocupa mais com o desempenho do pior caso do que com o desempenho médio do caso. Ele é garantido como O (N log N) e usa o espaço auxiliar O (1), o que significa que você não ficará inesperadamente sem espaço de pilha nem empilhará espaço em entradas muito grandes.
Introsort: Esta é uma classificação rápida que alterna para uma classificação de pilha após uma certa profundidade de recursão para contornar o pior caso de O (N ^ 2) da classificação rápida. É quase sempre melhor do que uma classificação rápida simples e antiga, já que você obtém o caso médio de uma classificação rápida, com desempenho garantido de O (N log N). Provavelmente, o único motivo para usar uma classificação de heap em vez disso é em sistemas com muita restrição de memória, nos quais o espaço de pilha O (log N) é praticamente significativo.
Classificação de inserção : quando N é garantidamente pequeno, inclusive como o caso base de uma classificação rápida ou de mesclagem. Embora seja O (N ^ 2), ele tem uma constante muito pequena e é um tipo estável.
Classificação por bolha, seleção : quando você está fazendo algo rápido e sujo e, por algum motivo, não pode usar o algoritmo de classificação da biblioteca padrão. A única vantagem que eles têm sobre a classificação por inserção é ser um pouco mais fácil de implementar.
Classificações sem comparação: sob algumas condições bastante limitadas, é possível quebrar a barreira O (N log N) e classificar em O (N). Aqui estão alguns casos em que vale a pena tentar:
Classificação de contagem: quando você classifica números inteiros com um intervalo limitado.
Classificação de raiz: quando log (N) é significativamente maior que K, onde K é o número de dígitos de raiz.
Classificação de intervalo: quando você pode garantir que sua entrada seja distribuída aproximadamente uniformemente.
fonte
O Quicksort geralmente é o mais rápido, em média, mas possui alguns comportamentos desagradáveis no pior dos casos. Portanto, se você precisar garantir que nenhum dado incorreto seja fornecido
O(N^2)
, evite-o.Classificação de mesclagem usa memória extra, mas é particularmente adequada para classificação externa (ou seja, arquivos enormes que não cabem na memória).
A classificação de heap pode classificar no local e não tem o pior comportamento quadrático, mas na média é mais lenta que a classificação rápida na maioria dos casos.
Onde apenas números inteiros em um intervalo restrito estão envolvidos, você pode usar algum tipo de classificação de raiz para torná-lo muito rápido.
Em 99% dos casos, você ficará bem com o tipo de biblioteca, que geralmente é baseado no quicksort.
fonte
A página da Wikipedia sobre algoritmos de classificação possui um ótimo gráfico de comparação.
http://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms
fonte
O que os links fornecidos para comparações / animações não consideram é quando a quantidade de dados excede a memória disponível - nesse ponto, o número de passagens sobre os dados, isto é, custos de E / S, dominam o tempo de execução. Se você precisar fazer isso, leia sobre "classificação externa", que geralmente cobre variantes de classificações de mesclagem e heap.
http://corte.si/posts/code/visualisingsorting/index.html e http://corte.si/posts/code/timsort/index.html também têm algumas imagens interessantes comparando vários algoritmos de classificação.
fonte
@dsimcha escreveu: Contando classificação: quando você está classificando números inteiros com um intervalo limitado
Eu mudaria isso para:
Classificação de contagem: quando você classifica números inteiros positivos (0 - Inteiro.MAX_VALUE-2 devido ao buraco de pombo).
Você sempre pode obter os valores max e min como uma heurística de eficiência em tempo linear também.
Além disso, você precisa de pelo menos n espaço extra para a matriz intermediária e é estável, obviamente.
(mesmo que isso permita MAX_VALUE-2), consulte: As matrizes Java têm um tamanho máximo?
Também explicaria que a complexidade da classificação de radix é O (wn) para n chaves que são números inteiros do tamanho da palavra w. Às vezes, w é apresentado como uma constante, o que tornaria a classificação de raiz melhor (para n suficientemente grande) do que os melhores algoritmos de classificação com base em comparação, que todos executam comparações O (n log n) para classificar n chaves. No entanto, em geral w não pode ser considerado uma constante: se todas as chaves n forem distintas, então w deve ser pelo menos log n para que uma máquina de acesso aleatório possa armazená-las na memória, o que oferece, na melhor das hipóteses, uma complexidade de tempo O (n log n). (da wikipedia)
fonte