Como Merge Sort, QuickSort é um algoritmo de divisão e conquista. Ele escolhe um elemento como pivô e particiona o array fornecido ao redor do pivô escolhido. Existem muitas versões diferentes do quickSort que selecionam o pivô de maneiras diferentes.
- Sempre escolha o primeiro elemento como pivô.
- Sempre escolha o último elemento como pivô (implementado abaixo)
- Escolha um elemento aleatório como pivô.
- Escolha mediana como pivô.
O processo chave no quickSort é partition (). O destino das partições é, dado uma matriz e um elemento x da matriz como pivô, colocar x em sua posição correta na matriz classificada e colocar todos os elementos menores (menores que x) antes de x, e colocar todos os elementos maiores (maiores que x) depois x. Tudo isso deve ser feito em tempo linear.
Pseudo código para função QuickSort recursiva:
Algoritmo de partição
Pode haver muitas maneiras de fazer a partição, seguindo o pseudo código que adota o método fornecido no livro CLRS. A lógica é simples, começamos do elemento mais à esquerda e acompanhamos o índice de elementos menores (ou iguais a) como i. Durante a travessia, se encontrarmos um elemento menor, trocamos o elemento atual com arr. Caso contrário, ignoraremos o elemento atual.
Pseudocódigo para partição ()
Ilustração de partição ():
Implementação:
A seguir estão as implementações do QuickSort:
Resultado:
Sorted array:1 5 7 8 9 10
Análise do QuickSort
O tempo gasto pelo QuickSort em geral pode ser escrito da seguinte forma.
T(n) = T(k) + T(n-k-1) + (n)
Os primeiros dois termos são para duas chamadas recursivas, o último termo é para o processo de partição. k é o número de elementos menores do que o pivô.
O tempo gasto pelo QuickSort depende da matriz de entrada e da estratégia de partição. A seguir estão três casos.
Pior caso: O pior caso ocorre quando o processo de partição sempre escolhe o maior ou o menor elemento como pivô. Se considerarmos a estratégia de partição acima, onde o último elemento é sempre escolhido como pivô, o pior caso ocorreria quando a matriz já estivesse classificada em ordem crescente ou decrescente. A seguir está a recorrência para o pior caso.
T(n) = T(0) + T(n-1) + (n)which is equivalent to T(n) = T(n-1) + (n)
A solução da recorrência acima é (n2).
Melhor caso: O melhor caso ocorre quando o processo de partição sempre escolhe o elemento do meio como pivô. A seguir está a recorrência para o melhor caso.
T(n) = 2T(n/2) + (n)
A solução da recorrência acima é (nLogn). Isso pode ser resolvido usando o caso 2 do Teorema Mestre.
Caso Médio:
Para fazer a análise de caso médio, precisamos considerar todas as permutações possíveis da matriz e calcular o tempo gasto por cada permutação que não parece fácil.
Podemos ter uma ideia do caso médio considerando o caso em que a partição coloca O (n / 9) elementos em um conjunto e O (9n / 10) elementos em outro. A seguir está a recorrência para este caso.
T(n) = T(n/9) + T(9n/10) + (n)
A solução da recorrência acima também é O (nLogn)
Embora o pior caso de complexidade de tempo do QuickSort seja O (n2) que é mais do que muitos outros algoritmos de classificação, como Merge Sort e Heap Sort, o QuickSort é mais rápido na prática, porque seu loop interno pode ser implementado com eficiência na maioria das arquiteturas e na maioria dos dados do mundo real. O QuickSort pode ser implementado de diferentes maneiras, alterando a escolha do pivô, de forma que o pior caso raramente ocorra para um determinado tipo de dados. No entanto, a classificação por mesclagem é geralmente considerada melhor quando os dados são enormes e armazenados em armazenamento externo.
O QuickSort é estável?
A implementação padrão não é estável. No entanto, qualquer algoritmo de classificação pode se tornar estável considerando os índices como parâmetro de comparação.
O QuickSort está no local?
De acordo com a ampla definição de algoritmo local, ele se qualifica como um algoritmo de classificação local, pois usa recursos extras espaço apenas para armazenar chamadas de função recursivas, mas não para manipular a entrada.
Como implementar QuickSort para listas vinculadas?
QuickSort em listas vinculadas simples
QuickSort na lista duplamente vinculada
Podemos implementar QuickSort iterativamente?
Sim, consulte a classificação rápida iterativa.
Por que a classificação rápida é preferível a MergeSort para classificar matrizes
A classificação rápida em sua forma geral é uma classificação local (ou seja, não requer nenhum armazenamento extra), enquanto a classificação por mesclagem requer O (N) armazenamento extra, N denotando o tamanho do array que pode ser bastante caro. Alocar e desalocar o espaço extra usado para a classificação por mesclagem aumenta o tempo de execução do algoritmo. Comparando a complexidade média, descobrimos que ambos os tipos de classificação têm complexidade média O (NlogN), mas as constantes são diferentes. Para arrays, a classificação por mesclagem perde devido ao uso de espaço de armazenamento O (N) extra.
A maioria das implementações práticas da Classificação rápida usa a versão aleatória. A versão randomizada tem complexidade de tempo esperada de O (nLogn).O pior caso também é possível na versão aleatória, mas o pior caso não ocorre para um determinado padrão (como matriz classificada) e a classificação rápida aleatória funciona bem na prática.
A classificação rápida também é uma classificação amigável de cache algoritmo, pois tem boa localidade de referência quando usado para matrizes.
A classificação rápida também é recursiva no final, portanto, otimizações de chamada final são feitas.
Por que MergeSort é preferível ao QuickSort para listas vinculadas ?
No caso de listas vinculadas, o caso é diferente principalmente devido à diferença na alocação de memória de matrizes e listas vinculadas. Ao contrário dos arrays, os nós da lista vinculada não podem ser adjacentes na memória. Ao contrário do array, na lista encadeada, podemos inserir itens no meio em O (1) espaço extra e O (1) tempo. Portanto, a operação de mesclagem de classificação de mesclagem pode ser implementada sem espaço extra para listas vinculadas.
Em arrays, podemos fazer acesso aleatório porque os elementos são contínuos na memória. Digamos que temos um array inteiro A (4 bytes) e que o endereço de A seja x, então para acessar A, podemos acessar diretamente a memória em (x + i * 4). Ao contrário dos arrays, não podemos fazer acesso aleatório na lista vinculada. A classificação rápida requer muito desse tipo de acesso. Na lista vinculada para acessar o iésimo índice, temos que viajar cada um dos nós da cabeça ao iésimo nó, pois não temos bloco contínuo de memória. Portanto, a sobrecarga aumenta para classificação rápida. A classificação por mesclagem acessa os dados sequencialmente e a necessidade de acesso aleatório é baixa.
Como otimizar o QuickSort para que ocupe O (Log n) espaço extra no pior caso?
Consulte Otimização de chamada de cauda do QuickSort (Reduzindo o espaço do pior caso para Log n)
Instantâneos:
- Teste no QuickSort
- Artigos recentes no QuickSort
- Prática de codificação para classificação.
Outros algoritmos de classificação no GeeksforGeeks / GeeksQuiz:
Classificação por seleção, classificação por bolha, classificação por inserção, classificação por mesclagem, classificação por heap, classificação rápida , Classificação de raiz, classificação de contagem, classificação de balde, classificação Shell, classificação de pente, classificação de buraco de pombo