Esta é uma repostagem de uma pergunta no cs.SE por Janoma . Créditos completos e despojos para ele ou cs.SE.
Em um curso padrão de algoritmos, aprendemos que o quicksort é O (n log n) em média e O (n²) no pior caso. Ao mesmo tempo, outros algoritmos de classificação são estudados, que são O (n log n) no pior caso (como mergesort e heapsort ) e até tempo linear no melhor caso (como bubblesort ), mas com algumas necessidades adicionais de memória.
Após uma rápida olhada em mais alguns tempos de execução , é natural dizer que o quicksort não deve ser tão eficiente quanto os outros.
Além disso, considere que os alunos aprendem nos cursos básicos de programação que a recursão não é realmente boa em geral, porque poderia usar muita memória, etc. Portanto (e mesmo que este não seja um argumento real), isso dá a ideia de que o quicksort pode não ser muito bom porque é um algoritmo recursivo.
Por que, então, o quicksort supera outros algoritmos de classificação na prática? Isso tem a ver com a estrutura dos dados do mundo real ? Isso tem a ver com o modo como a memória funciona nos computadores? Sei que algumas memórias são muito mais rápidas que outras, mas não sei se essa é a verdadeira razão desse desempenho contra-intuitivo (quando comparado às estimativas teóricas).
fonte
Respostas:
Não concordo que o quicksort seja melhor do que outros algoritmos de classificação na prática.
Para a maioria das finalidades, Timsort - o híbrido entre a classificação de fusão / inserção que explora o fato de que os dados que você classifica geralmente começam quase classificados ou classificados inversamente.
O quicksort mais simples (sem pivô aleatório) trata esse caso potencialmente comum como O (N ^ 2) (reduzindo para O (N lg N) com pivôs aleatórios), enquanto o TimSort pode lidar com esses casos em O (N).
De acordo com esses benchmarks em C # que comparam o quicksort interno ao TimSort, o Timsort é significativamente mais rápido nos casos mais classificados e um pouco mais rápido no caso de dados aleatórios e o TimSort melhora se a função de comparação for particularmente lenta. Não repeti esses benchmarks e não ficaria surpreso se o quicksort superasse levemente o TimSort por alguma combinação de dados aleatórios ou se houvesse algo peculiar no tipo interno do C # (com base no quicksort) que o estivesse atrasando. No entanto, o TimSort possui vantagens distintas quando os dados podem ser classificados parcialmente e é aproximadamente igual ao quicksort em termos de velocidade quando os dados não são classificados parcialmente.
O TimSort também possui um bônus adicional de ser um tipo estável, ao contrário do quicksort. A única desvantagem do TimSort usa memória O (N) versus O (lg N) na implementação usual (rápida).
fonte
A ordenação rápida é considerada mais rápida porque o coeficiente é menor que qualquer outro algoritmo conhecido. Não há razão ou prova disso, apenas nenhum algoritmo com um coeficiente menor foi encontrado. É verdade que outros algoritmos também têm tempo O ( n log n ), mas no mundo real o coeficiente também é importante.
Observe que, para classificação de inserção de dados pequena (a que é considerada O ( n 2 )), é mais rápida devido à natureza das funções matemáticas. Isso depende dos coeficientes específicos que variam de máquina para máquina. (No final, apenas a montagem está realmente em execução.) Portanto, às vezes, um híbrido de ordenação rápida e ordenação por inserção é o mais rápido na prática.
fonte
O Quicksort não supera todos os outros algoritmos de classificação. Por exemplo, a classificação de pilha ascendente ( Wegener 2002 ) supera a classificação rápida para quantidades razoáveis de dados e também é um algoritmo no local. Também é fácil de implementar (pelo menos, não mais difícil do que alguma variante de quicksort otimizada).
Não é tão conhecido e você não o encontra em muitos livros, o que pode explicar por que não é tão popular quanto o quicksort.
fonte
Você não deve se concentrar apenas no pior dos casos e apenas na complexidade do tempo. É mais sobre média do que pior, e é sobre tempo e espaço.
Ordenação rápida:
Também leve em consideração que a grande notação O não leva em consideração nenhuma constante, mas na prática faz diferença se o algoritmo for algumas vezes mais rápido. Θ ( n log n ) significa que o algoritmo é executado em K n log ( n ), onde K é constante. Quicksort é o algoritmo de comparação de-espécie com o menor K .
fonte
O Quicksort geralmente é uma boa escolha, pois é razoavelmente rápido, razoavelmente rápido e fácil de implementar.
Se você é sério sobre a classificação de grandes quantidades de dados muito rapidamente, provavelmente é melhor usar algumas variações no MergeSort. Isso pode ser feito para tirar proveito do armazenamento externo, pode fazer uso de vários threads ou até processos, mas eles não são triviais para o código.
fonte
O desempenho real dos algoritmos depende da plataforma, bem como da linguagem, do compilador, da atenção do programador aos detalhes da implementação, do esforço específico de otimização etc. Portanto, a "vantagem constante do fator" do quicksort não é muito bem definida - é um julgamento subjetivo baseado nas ferramentas atualmente disponíveis e uma estimativa aproximada do "esforço equivalente de implementação" por quem realmente faz o estudo de desempenho comparativo. .
Dito isso, acredito que o quicksort tem um bom desempenho (para entrada aleatória) porque é simples e porque sua estrutura recursiva é relativamente compatível com o cache. Por outro lado, como seu pior caso é fácil de acionar, qualquer uso prático de uma classificação rápida precisará ser mais complexo do que a descrição de seu livro indicaria: assim, versões modificadas, como a introsort.
Com o tempo, à medida que a plataforma dominante muda, diferentes algoritmos podem ganhar ou perder sua vantagem relativa (mal definida). A sabedoria convencional sobre o desempenho relativo pode ficar para trás dessa mudança; portanto, se você não tiver certeza de qual algoritmo é melhor para o seu aplicativo, implemente os dois e teste-os.
fonte