Existem dois métodos de partição quicksort mencionados em Cormen:
Hoare-Partition(A, p, r)
x = A[p]
i = p - 1
j = r + 1
while true
repeat
j = j - 1
until A[j] <= x
repeat
i = i + 1
until A[i] >= x
if i < j
swap( A[i], A[j] )
else
return j
e:
Lomuto-Partition(A, p, r)
x = A[r]
i = p - 1
for j = p to r - 1
if A[j] <= x
i = i + 1
swap( A[i], A[j] )
swap( A[i +1], A[r] )
return i + 1
Desconsiderando o método de escolha do pivô, em que situações uma é preferível à outra? Eu sei, por exemplo, que o Lomuto pré-forma relativamente mal quando há uma alta porcentagem de valores duplicados (ou seja, onde digamos que mais de 2/3 da matriz é o mesmo valor), onde Hoare se sai bem nessa situação.
Que outros casos especiais tornam um método de partição significativamente melhor que o outro?
algorithms
sorting
quicksort
Robert S. Barnes
fonte
fonte
A[i+1] <= x
. Em uma matriz classificada (e tendo em vista os pivôs razoavelmente escolhidos), Hoare quase não troca e Lomuto faz uma tonelada (uma vez que j fica pequeno o suficiente, então todosA[j] <= x
). O que estou perdendo?swap(A[p], A[j])
no final do Hoare's para obter o mesmo comportamento para ambos.i < j
nos 2 loops de repetição do particionamento do Hoare.Respostas:
Dimensão Pedagógica
Devido à sua simplicidade, o método de particionamento do Lomuto pode ser mais fácil de implementar. Há uma boa anedota em Programming Pearl, de Jon Bentley, sobre Classificação:
Dimensão de desempenho
Para uso prático, a facilidade de implementação pode ser sacrificada em prol da eficiência. Em uma base teórica, podemos determinar o número de comparações e swaps de elementos para comparar o desempenho. Além disso, o tempo de execução real será influenciado por outros fatores, como desempenho do cache e previsões incorretas de ramificações.
Como mostrado abaixo, os algoritmos se comportam de maneira muito semelhante em permutações aleatórias, exceto pelo número de swaps . Lá, Lomuto precisa de três vezes mais que Hoare!
Número de comparações
Número de Swaps
O número de trocas é aleatório para os dois algoritmos, dependendo dos elementos na matriz. Se assumirmos permutações aleatórias , ou seja, todos os elementos são distintos e toda permutação dos elementos é igualmente provável, podemos analisar o número esperado de swaps.
Método de Lomuto
Método de Hoare
Por fim, calculamos a média novamente de todos os valores de pivô para obter o número geral esperado de swaps para o particionamento de Hoare:
(Uma descrição mais detalhada pode ser encontrada na minha tese de mestrado , página 29.)
Padrão de acesso à memória
Ambos os algoritmos usam dois ponteiros na matriz que a varrem sequencialmente . Portanto, ambos se comportam em cache wrt quase ideal.
Elementos iguais e listas já ordenadas
Como já mencionado pela Wandering Logic, o desempenho dos algoritmos difere drasticamente para listas que não são permutações aleatórias.
A[j] <= x
Conclusão
O método do Lomuto é simples e fácil de implementar, mas não deve ser usado para implementar um método de classificação de bibliotecas.
fonte
Alguns comentários foram adicionados à excelente resposta de Sebastian.
Vou falar sobre o algoritmo de rearranjos de partição em geral e não sobre seu uso específico para o Quicksort .
Estabilidade
O algoritmo de Lomuto é semi - estável : a ordem relativa dos elementos que não satisfazem o predicado é preservada. O algoritmo de Hoare é instável.
Padrão de acesso ao elemento
O algoritmo do Lomuto pode ser usado com lista vinculada única ou estruturas de dados somente para frente semelhantes. O algoritmo de Hoare precisa de bidirecionalidade .
Número de comparações
Mas, para fazer isso, temos que sacrificar 2 propriedades:
fonte