O Quicksort é descrito como "no local", mas usando uma implementação como:
def sort(array):
less = []
equal = []
greater = []
if len(array) > 1:
pivot = array[0]
for x in array:
if x < pivot:
less.append(x)
if x == pivot:
equal.append(x)
if x > pivot:
greater.append(x)
return sort(less) + equal + sort(greater)
else:
return array
Você precisa criar uma cópia da lista para cada recursão. No primeiro retorno, na memória, temos:
- matriz
- maior + igual + menos
Então, pela segunda recursão em todas as sub-listas, temos:
- matriz
- maior, igual, menor desde a primeira recursão
- maior + igual + menor de menor1, maior + igual + menor de maior1
etc ...
É apenas um código mal escrito ou estou correto ao pensar que, para uma grande lista, você realmente precisa ter, proporcionalmente, uma quantidade razoável de espaço extra para armazenar esses itens?
Quando penso em algo "in-loco", penso na classificação de bolhas, que simplesmente troca elementos da lista como: http://en.wikipedia.org/wiki/File:Bubble-sort-example-300px. gif
O BubbleSort requer apenas 1 variável extra para armazenar um elemento potencialmente trocado.
algorithms
sorting
quicksort
LittleBobbyTables
fonte
fonte
Respostas:
Essa implementação específica do quicksort não está em vigor. Ele trata a estrutura de dados como uma lista que só pode crescer em uma direção (nesse caso, uma classificação de mesclagem seria mais simples e rápida). No entanto, é possível escrever uma implementação no local do quicksort, e é dessa maneira que geralmente é apresentada.
Em uma implementação no local, a função de classificação não é chamada recursivamente em matrizes recém-construídas que se tornam cada vez menores, mas em limites que se aproximam cada vez mais.
(Cuidado com este código, eu apenas o digitei, não o provei. Quaisquer erros pontuais são seus para corrigir. As implementações do mundo real usariam um algoritmo diferente para tamanhos pequenos, mas isso não afeta o comportamento assintótico. Real As implementações do -world escolheriam um pivô melhor, mas não abordarei isso aqui, pois não é realmente para esta pergunta.)
A página da Wikipedia apresenta uma versão não in-loco e in-loco do algoritmo.
O Quicksort, conforme escrito aqui, requer armazenamento extra de , onde é a profundidade da recursão (que depende da qualidade do pivô) é o tamanho do elemento. O requisito de tamanho da pilha pode ser aprimorado: há duas chamadas recursivas e podemos fazer da segunda uma chamada final (que não consome nenhuma pilha). Se sempre fizermos a chamada recursiva na metade menor primeiro, o tamanho máximo da pilha para comprimentos de matriz até satisfaz com , então . Assim, podemos atingir os requisitos de armazenamento extra de , independentemente da opção de pivô.O(d)+s d s n S^(n)≤S^(m) m≤n/2≤S^(n/2) S^(n)≤lg2(n)S^(1) O(logn)+s
Existem muitos outros algoritmos de classificação que podem ser implementados no local, incluindo classificação de inserção, classificação e seleção de heap. A forma simples de classificação por mesclagem não está no lugar, mas existe uma variante mais sofisticada .
Agradecemos a Aryabhata por apontar que o Quicksort sempre pode ser feito na pilha e que existe uma variante de classificação de mesclagem com armazenamento adicional e tempo de execução .lg(n) O(1) O(nlog(n))
fonte
Além da resposta de Gilles, você também pode instalar o Quicksort com seu código, se você usar listas vinculadas em vez de matrizes. Apenas remova o elemento da lista original ao anexá-lo a uma das listas menores.
O seguinte pseudocódigo assume / garante:
new list
cria uma lista que consiste em uma cabeça com oNIL
próximo ponteiro.sort
leva um ponteiro para uma cabeça e retorna um ponteiro para o último elemento da lista classificada. O ponteiro fornecido como argumento também é o cabeçalho da lista classificada..
Embora exista alguma otimização possível a partir do código acima, esta implementação possui uma sobrecarga de memória maior que a implementação baseada em array na resposta de Gilles. Além disso, sofre na prática do problema de que as listas vinculadas geralmente são menos localizadas e, portanto, induzem um número maior de falhas de cache do que a manutenção dos mesmos dados em uma matriz.
No entanto, essa implementação é vantajosa, se você precisar manter ponteiros para os elementos através da classificação. Também é bom estar ciente disso, se você estiver armazenando seus dados em uma lista vinculada por motivos não relacionados à classificação. (Se o local da classificação é motivo de preocupação, a conversão entre lista e matriz provavelmente está fora de questão.)
fonte