Eu sou totalmente novo em python e estou tentando implementar o quicksort nele. Alguém poderia me ajudar a completar meu código?
Não sei como concatenar os três arrays e imprimi-los.
def sort(array=[12,4,5,6,7,3,1,15]):
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)
sort(less)
sort(pivot)
sort(greater)
my_list = list1 + list2 + ...
. Ou descompacte listas para uma nova listamy_list = [*list1, *list2]
Respostas:
fonte
if
s no loop for comelif
eelse
para evitar fazer comparações desnecessáriasClassificação rápida sem memória adicional (no local)
Uso:
fonte
if end is None:
vai ser verificado várias vezes, e apenas uma vezTrue
. Você deve colocar isso em uma função de wrapper para que seja chamado apenas uma vez.array[pivot], array[begin] = array[begin], array[pivot]
deve substituirbegin
porend
.Existe outra versão concisa e bonita
Deixe-me explicar os códigos acima para obter detalhes
escolha o primeiro elemento da matriz
arr[0]
como pivô[arr[0]]
qsort
aqueles elementos da matriz que são menos do que pivô comList Comprehension
qsort([x for x in arr[1:] if x < arr[0]])
qsort
aqueles elementos da matriz que são maiores do que o pivô comList Comprehension
qsort([x for x in arr[1:] if x >= arr[0]])
fonte
sorted
, isso é claramente para fins educacionais. E é legível, mais legível do que a resposta aceita.Esta resposta é um QuickSort local para
Python 2.x
. Minha resposta é uma interpretação da solução in-loco do Rosetta Code que também funciona paraPython 3
:E se você estiver disposto a abrir mão da propriedade no local, abaixo está outra versão que ilustra melhor as idéias básicas por trás do quicksort. Além da legibilidade, sua outra vantagem é que ele é estável (elementos iguais aparecem na lista classificada na mesma ordem que costumavam aparecer na lista não classificada). Esta propriedade de estabilidade não se mantém com a implementação local que consome menos memória apresentada acima.
fonte
Na vida real, devemos sempre usar a classificação embutida fornecida pelo Python. No entanto, compreender o algoritmo de classificação rápida é instrutivo.
Meu objetivo aqui é quebrar o assunto de forma que seja facilmente entendido e replicável pelo leitor sem ter que retornar aos materiais de referência.
O algoritmo quicksort é essencialmente o seguinte:
Se os dados forem distribuídos aleatoriamente, selecionar o primeiro ponto de dados como o pivô é equivalente a uma seleção aleatória.
Exemplo legível:
Primeiro, vamos olhar um exemplo legível que usa comentários e nomes de variáveis para apontar para valores intermediários:
Para reafirmar o algoritmo e o código demonstrado aqui - movemos os valores acima do pivô para a direita e os valores abaixo do pivô para a esquerda e, em seguida, passamos essas partições para a mesma função para serem classificados posteriormente.
Jogado golfe:
Isso pode ser definido para 88 caracteres:
Para ver como chegamos lá, primeiro pegue nosso exemplo legível, remova comentários e docstrings e encontre o pivô no local:
Agora encontre abaixo e acima, no local:
Agora, sabendo que
and
retorna o elemento anterior se falso, senão, se for verdadeiro, avalia e retorna o seguinte elemento, temos:Já que lambdas retornam uma única epressão, e nós simplificamos para uma única expressão (embora esteja ficando mais ilegível), agora podemos usar um lambda:
E para reduzir ao nosso exemplo, reduza os nomes das funções e variáveis para uma letra e elimine os espaços em branco desnecessários.
Observe que este lambda, como a maioria dos códigos de golfe, é um estilo bastante ruim.
Quicksort no local, usando o esquema de particionamento Hoare
A implementação anterior cria muitas listas extras desnecessárias. Se pudermos fazer isso no local, evitaremos o desperdício de espaço.
A implementação abaixo usa o esquema de particionamento Hoare, sobre o qual você pode ler mais na wikipedia (mas aparentemente removemos até 4 cálculos redundantes por
partition()
chamada usando a semântica while-loop em vez de do-while e movendo as etapas de redução para o final de o loop while externo.).Não tenho certeza se testei exaustivamente:
Conclusão
Esse algoritmo é freqüentemente ensinado em cursos de ciência da computação e solicitado em entrevistas de emprego. Isso nos ajuda a pensar sobre recursão e dividir para conquistar.
Quicksort não é muito prático em Python, pois nosso algoritmo timsort embutido é bastante eficiente e temos limites de recursão. Esperaríamos classificar as listas no local com
list.sort
ou criar novas listas classificadas comsorted
- ambas as quais recebem um argumentokey
ereverse
.fonte
partition
função parecem não funcionar corretamente para:partition([5,4,3,2,1], 0, 4)
. O índice de retorno esperado é 4, enquanto retorna 3.Já existem muitas respostas para isso, mas acho que essa abordagem é a implementação mais limpa:
Você pode, é claro, pular o armazenamento de tudo em variáveis e retorná-las imediatamente assim:
fonte
O(N!)
? Supondo que a lista aninhada[lesser]
e[greater]
erros de digitação, não seria a médiaO(3N logN)
que se reduziria à média esperadaO(N logN)
? Concedido, os 3 componentes de lista fazem um trabalho desnecessário ..abordagem funcional:
fonte
abordagem de programação funcional
fonte
Fácil implementação de algoritmos de grokking
fonte
Acho que ambas as respostas aqui funcionam bem para a lista fornecida (que responde à pergunta original), mas quebraria se uma matriz contendo valores não exclusivos for passada. Portanto, para completar, gostaria apenas de apontar o pequeno erro em cada um e explicar como corrigi-los.
Por exemplo, tentando classificar a seguinte matriz [12,4,5,6,7,3,1,15,1] (Observe que 1 aparece duas vezes) com o algoritmo de Brionius .. em algum ponto terminará com menos matriz vazia e a matriz igual com um par de valores (1,1) que não podem ser separados na próxima iteração e len ()> 1 ... portanto, você acabará com um loop infinito
Você pode consertar retornando array se less estiver vazio ou melhor não chamando sort em seu array igual, como em zangw answer
A solução mais sofisticada também quebra, mas por uma causa diferente, está faltando o retorno cláusula de na linha de recursão, o que fará com que em algum ponto retorne Nenhum e tente anexá-lo a uma lista ....
Para corrigir, basta adicionar um retorno a essa linha
fonte
Esta é uma versão do quicksort usando o esquema de partição Hoare e com menos trocas e variáveis locais
fonte
Partição - Divide uma matriz por um pivô que os elementos menores se movem para a esquerda e os elementos maiores se movem para a direita ou vice-versa. Um pivô pode ser um elemento aleatório de uma matriz. Para fazer esse algoritmo, precisamos saber o que é o índice inicial e final de uma matriz e onde está um pivô. Em seguida, defina dois ponteiros auxiliares L, R.
Portanto, temos um usuário de array [..., começo, ..., fim, ...]
A posição inicial dos ponteiros L e R
[..., começar, próximo, ..., fim, ...]
R L
enquanto L <fim
1. Se um usuário [pivô]> usuário [L] então mova R por um e troque o usuário [R] pelo usuário [L]
2. mova L por um
Depois de algum tempo, troque o usuário [R] com o usuário [pivot]
Classificação rápida - Use o algoritmo de partição até que cada parte seguinte da divisão por um pivô tenha um índice inicial maior ou igual ao índice final.
fonte
Ou se você preferir uma linha que também ilustra o equivalente em Python de varags C / C ++, expressões lambda e expressões if:
fonte
fonte
Sei que muitas pessoas responderam a essa pergunta corretamente e gostei de lê-las. Minha resposta é quase a mesma que zangw, mas acho que os contribuidores anteriores não fizeram um bom trabalho explicando visualmente como as coisas realmente funcionam ... então aqui está minha tentativa de ajudar outras pessoas que podem visitar esta pergunta / respostas no futuro sobre um solução simples para implementação de quicksort.
Como funciona ?
Aqui está um exemplo junto com o visual para acompanhar ... (pivô) 9,11,2,0
média: n log de n
pior caso: n ^ 2
O código:
itens = [9,11,2,0] imprimir (classificação rápida (itens))
fonte
fonte
fonte
Uma implementação "verdadeira" no local [Algoritmos 8.9, 8.11 do Livro de Design e Aplicações de Algoritmos de Michael T. Goodrich e Roberto Tamassia]:
fonte
O algoritmo possui 4 etapas simples:
Código para o algoritmo em python:
Continue com este algoritmo recursivamente com as partes esquerda e direita.
fonte
Outra implementação de quicksort:
fonte
Para a versão Python 3.x : um
operator
módulo de uso de estilo funcional , principalmente para melhorar a legibilidade.e é testado como
fonte
… complete my code?
. Usarlambda
para definirsublist()
não parece estritamente necessário.sublist
ser definido apenas usandofilter
? É mesmo possível?def
- não comecei a mexer ainda enquanto estou tentando descobrir se há uma maneira mais eficiente de "distribuir" os elementos de um iterável para separar listas (ou, alternativamente, uma lista com uma " categoria "após o outro).)Esta é uma implementação fácil: -
fonte
O algoritmo contém dois limites, um com elementos menores que o pivô (rastreado pelo índice "j") e o outro tendo elementos maiores que o pivô (rastreado pelo índice "i").
Em cada iteração, um novo elemento é processado incrementando j.
Invariante:-
Se o invariante for violado, os elementos i e j são trocados e i é incrementado.
Depois que todos os elementos foram processados e tudo após o pivô ter sido particionado, o elemento pivô é trocado pelo último elemento menor do que ele.
O elemento pivô agora estará em seu lugar correto na sequência. Os elementos anteriores serão menores do que ele e os posteriores serão maiores do que ele e não serão classificados.
Selecionando um pivô
Um pivô "bom" resultará em duas subseqüências de aproximadamente o mesmo tamanho. Deterministicamente, um elemento pivô pode ser selecionado de uma maneira ingênua ou calculando a mediana da sequência.
Uma implementação ingênua de selecionar um pivô será o primeiro ou o último elemento. O pior caso de tempo de execução, neste caso, será quando a sequência de entrada já estiver classificada ou classificada reversamente, pois uma das subsequências estará vazia, o que fará com que apenas um elemento seja removido por chamada recursiva.
Uma divisão perfeitamente equilibrada é obtida quando o pivô é o elemento mediano da sequência. Há um número igual de elementos maior e menor do que ele. Essa abordagem garante um melhor tempo de execução geral, mas é muito mais demorada.
Uma maneira não determinística / aleatória de selecionar o pivô seria escolher um elemento uniformemente ao acaso. Esta é uma abordagem simples e leve que minimizará o pior cenário e também levará a uma divisão aproximadamente equilibrada. Isso também fornecerá um equilíbrio entre a abordagem ingênua e a abordagem mediana de seleção do pivô.
fonte
Estou anexando o código abaixo! Este quicksort é uma ótima ferramenta de aprendizado devido à localização do valor pivô . Como ele está em um lugar constante, você pode percorrê-lo várias vezes e realmente pegar o jeito de como tudo funciona. Na prática, é melhor randomizar o pivô para evitar o tempo de execução O (N ^ 2).
fonte
fonte
Exemplo completo com variáveis impressas na etapa de partição:
fonte
fonte
Este algoritmo não usa funções recursivas.
Let
N
Ser qualquer lista de números comlen(N) > 0
. ConjuntoK = [N]
e execute o seguinte programa.Nota: este é um algoritmo de classificação estável .
fonte
Provavelmente apenas uma questão de preferência, mas gosto de adicionar validação ao topo das minhas funções.
fonte
Minha resposta é muito parecida com a grande do @alisianoi. No entanto, acredito que haja uma ligeira ineficiência em seu código (veja meu comentário), que removi. Além disso, acrescentei mais explicações e fui um pouco mais específico sobre o problema de valores duplicados (pivô).
fonte