Soy totalmente nuevo en Python y estoy tratando de implementar quicksort en él. ¿Podría alguien ayudarme a completar mi código?
No sé cómo concatenar las tres matrices e imprimirlas.
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 + ...
. O descomprima listas en una nueva listamy_list = [*list1, *list2]
Respuestas:
def sort(array=[12,4,5,6,7,3,1,15]): """Sort the array by using quicksort.""" less = [] equal = [] greater = [] if len(array) > 1: pivot = array[0] for x in array: if x < pivot: less.append(x) elif x == pivot: equal.append(x) elif x > pivot: greater.append(x) # Don't forget to return something! return sort(less)+equal+sort(greater) # Just use the + operator to join lists # Note that you want equal ^^^^^ not pivot else: # You need to handle the part at the end of the recursion - when you only have one element in your array, just return the array. return array
fuente
if
s en el bucle for conelif
yelse
para evitar comparaciones innecesariasClasificación rápida sin memoria adicional (en su lugar)
Uso:
array = [97, 200, 100, 101, 211, 107] quicksort(array) # array -> [97, 100, 101, 107, 200, 211]
def partition(array, begin, end): pivot = begin for i in xrange(begin+1, end+1): if array[i] <= array[begin]: pivot += 1 array[i], array[pivot] = array[pivot], array[i] array[pivot], array[begin] = array[begin], array[pivot] return pivot def quicksort(array, begin=0, end=None): if end is None: end = len(array) - 1 def _quicksort(array, begin, end): if begin >= end: return pivot = partition(array, begin, end) _quicksort(array, begin, pivot-1) _quicksort(array, pivot+1, end) return _quicksort(array, begin, end)
fuente
if end is None:
va a ser revisado muchas veces, y solo una vezTrue
. Debe poner esto en una función contenedora para que solo se llame una vez.array[pivot], array[begin] = array[begin], array[pivot]
debe reemplazarsebegin
conend
.Hay otra versión concisa y hermosa.
def qsort(arr): if len(arr) <= 1: return arr else: return qsort([x for x in arr[1:] if x < arr[0]]) + \ [arr[0]] + \ qsort([x for x in arr[1:] if x >= arr[0]]) # this comment is just to improve readability due to horizontal scroll!!!
Déjame explicarte los códigos anteriores para obtener más detalles.
elige el primer elemento de la matriz
arr[0]
como pivote[arr[0]]
qsort
aquellos elementos de la matriz que son menos de pivote conList Comprehension
qsort([x for x in arr[1:] if x < arr[0]])
qsort
aquellos elementos de la matriz que son más grandes que pivote conList Comprehension
qsort([x for x in arr[1:] if x >= arr[0]])
fuente
sorted
, esto es claramente con fines educativos. Y es legible, más legible que la respuesta aceptada.Esta respuesta es un QuickSort in situ para
Python 2.x
. Mi respuesta es una interpretación de la solución en el lugar de Rosetta Code que también funciona paraPython 3
:import random def qsort(xs, fst, lst): ''' Sort the range xs[fst, lst] in-place with vanilla QuickSort :param xs: the list of numbers to sort :param fst: the first index from xs to begin sorting from, must be in the range [0, len(xs)) :param lst: the last index from xs to stop sorting at must be in the range [fst, len(xs)) :return: nothing, the side effect is that xs[fst, lst] is sorted ''' if fst >= lst: return i, j = fst, lst pivot = xs[random.randint(fst, lst)] while i <= j: while xs[i] < pivot: i += 1 while xs[j] > pivot: j -= 1 if i <= j: xs[i], xs[j] = xs[j], xs[i] i, j = i + 1, j - 1 qsort(xs, fst, j) qsort(xs, i, lst)
Y si está dispuesto a renunciar a la propiedad in situ, a continuación se muestra otra versión que ilustra mejor las ideas básicas detrás de la ordenación rápida. Además de la legibilidad, su otra ventaja es que es estable (los elementos iguales aparecen en la lista ordenada en el mismo orden que solían tener en la lista sin clasificar). Esta propiedad de estabilidad no se mantiene con la implementación local que consume menos memoria y que se presentó anteriormente.
def qsort(xs): if not xs: return xs # empty sequence case pivot = xs[random.choice(range(0, len(xs)))] head = qsort([x for x in xs if x < pivot]) tail = qsort([x for x in xs if x > pivot]) return head + [x for x in xs if x == pivot] + tail
fuente
En la vida real, siempre deberíamos usar el tipo integrado proporcionado por Python. Sin embargo, comprender el algoritmo de clasificación rápida es instructivo.
Mi objetivo aquí es desglosar el tema de tal manera que el lector pueda entenderlo y reproducirlo fácilmente sin tener que volver a los materiales de referencia.
El algoritmo de clasificación rápida es esencialmente el siguiente:
Si los datos se distribuyen aleatoriamente, seleccionar el primer punto de datos como pivote equivale a una selección aleatoria.
Ejemplo legible:
Primero, veamos un ejemplo legible que usa comentarios y nombres de variables para señalar valores intermedios:
def quicksort(xs): """Given indexable and slicable iterable, return a sorted list""" if xs: # if given list (or tuple) with one ordered item or more: pivot = xs[0] # below will be less than: below = [i for i in xs[1:] if i < pivot] # above will be greater than or equal to: above = [i for i in xs[1:] if i >= pivot] return quicksort(below) + [pivot] + quicksort(above) else: return xs # empty list
Para reformular el algoritmo y el código que se muestran aquí, movemos los valores por encima del pivote a la derecha y los valores por debajo del pivote a la izquierda, y luego pasamos esas particiones a la misma función para que se clasifiquen más.
Jugado al golf:
Esto se puede jugar al golf hasta 88 caracteres:
q=lambda x:x and q([i for i in x[1:]if i<=x[0]])+[x[0]]+q([i for i in x[1:]if i>x[0]])
Para ver cómo llegamos allí, primero tome nuestro ejemplo legible, elimine los comentarios y las cadenas de documentos, y busque el pivote en su lugar:
def quicksort(xs): if xs: below = [i for i in xs[1:] if i < xs[0]] above = [i for i in xs[1:] if i >= xs[0]] return quicksort(below) + [xs[0]] + quicksort(above) else: return xs
Ahora busque abajo y arriba, en el lugar:
def quicksort(xs): if xs: return (quicksort([i for i in xs[1:] if i < xs[0]] ) + [xs[0]] + quicksort([i for i in xs[1:] if i >= xs[0]])) else: return xs
Ahora, sabiendo que
and
devuelve el elemento anterior si es falso, de lo contrario si es verdadero, evalúa y devuelve el siguiente elemento, tenemos:def quicksort(xs): return xs and (quicksort([i for i in xs[1:] if i < xs[0]] ) + [xs[0]] + quicksort([i for i in xs[1:] if i >= xs[0]]))
Dado que las lambdas devuelven una sola expresión, y lo hemos simplificado a una sola expresión (aunque se está volviendo más ilegible) ahora podemos usar una lambda:
quicksort = lambda xs: (quicksort([i for i in xs[1:] if i < xs[0]] ) + [xs[0]] + quicksort([i for i in xs[1:] if i >= xs[0]]))
Y para reducir a nuestro ejemplo, acorte los nombres de las funciones y variables a una letra y elimine los espacios en blanco que no son necesarios.
q=lambda x:x and q([i for i in x[1:]if i<=x[0]])+[x[0]]+q([i for i in x[1:]if i>x[0]])
Tenga en cuenta que esta lambda, como la mayoría de los códigos de golf, tiene un estilo bastante malo.
Ordenación rápida en el lugar, utilizando el esquema de particionamiento Hoare
La implementación anterior crea muchas listas adicionales innecesarias. Si podemos hacer esto en el lugar, evitaremos desperdiciar espacio.
La siguiente implementación usa el esquema de partición de Hoare, sobre el cual puede leer más en wikipedia (pero aparentemente hemos eliminado hasta 4 cálculos redundantes por
partition()
llamada usando la semántica de bucle while en lugar de do-while y moviendo los pasos de reducción al final de el bucle externo while.).def quicksort(a_list): """Hoare partition scheme, see https://en.wikipedia.org/wiki/Quicksort""" def _quicksort(a_list, low, high): # must run partition on sections with 2 elements or more if low < high: p = partition(a_list, low, high) _quicksort(a_list, low, p) _quicksort(a_list, p+1, high) def partition(a_list, low, high): pivot = a_list[low] while True: while a_list[low] < pivot: low += 1 while a_list[high] > pivot: high -= 1 if low >= high: return high a_list[low], a_list[high] = a_list[high], a_list[low] low += 1 high -= 1 _quicksort(a_list, 0, len(a_list)-1) return a_list
No estoy seguro si lo probé lo suficientemente a fondo:
def main(): assert quicksort([1]) == [1] assert quicksort([1,2]) == [1,2] assert quicksort([1,2,3]) == [1,2,3] assert quicksort([1,2,3,4]) == [1,2,3,4] assert quicksort([2,1,3,4]) == [1,2,3,4] assert quicksort([1,3,2,4]) == [1,2,3,4] assert quicksort([1,2,4,3]) == [1,2,3,4] assert quicksort([2,1,1,1]) == [1,1,1,2] assert quicksort([1,2,1,1]) == [1,1,1,2] assert quicksort([1,1,2,1]) == [1,1,1,2] assert quicksort([1,1,1,2]) == [1,1,1,2]
Conclusión
Este algoritmo se enseña con frecuencia en cursos de informática y se solicita en entrevistas de trabajo. Nos ayuda a pensar en la recursividad y el divide y vencerás.
Quicksort no es muy práctico en Python ya que nuestro algoritmo de ordenación de tiempos incorporado es bastante eficiente y tenemos límites de recursividad. Esperaríamos ordenar listas en el lugar con
list.sort
o crear nuevas listas ordenadas consorted
, las cuales toman un argumentokey
yreverse
.fuente
partition
función parece no funcionar correctamente para:partition([5,4,3,2,1], 0, 4)
. El índice de rendimiento esperado es 4, mientras que devuelve 3.Ya hay muchas respuestas a esto, pero creo que este enfoque es la implementación más limpia:
def quicksort(arr): """ Quicksort a list :type arr: list :param arr: List to sort :returns: list -- Sorted list """ if not arr: return [] pivots = [x for x in arr if x == arr[0]] lesser = quicksort([x for x in arr if x < arr[0]]) greater = quicksort([x for x in arr if x > arr[0]]) return lesser + pivots + greater
Por supuesto, puede omitir el almacenamiento de todo en variables y devolverlas de inmediato de esta manera:
def quicksort(arr): """ Quicksort a list :type arr: list :param arr: List to sort :returns: list -- Sorted list """ if not arr: return [] return quicksort([x for x in arr if x < arr[0]]) \ + [x for x in arr if x == arr[0]] \ + quicksort([x for x in arr if x > arr[0]])
fuente
O(N!)
? Suponiendo que la lista anidada[lesser]
y[greater]
hay errores tipográficos, ¿no sería un promedioO(3N logN)
que se reduciría al promedio esperadoO(N logN)
? De acuerdo, las 3 composiciones de la lista hacen un trabajo innecesario.enfoque funcional:
def qsort(list): if len(list) < 2: return list pivot = list.pop() left = filter(lambda x: x <= pivot, list) right = filter(lambda x: x > pivot, list) return qsort(left) + [pivot] + qsort(right)
fuente
enfoque de programación funcional
smaller = lambda xs, y: filter(lambda x: x <= y, xs) larger = lambda xs, y: filter(lambda x: x > y, xs) qsort = lambda xs: qsort(smaller(xs[1:],xs[0])) + [xs[0]] + qsort(larger(xs[1:],xs[0])) if xs != [] else [] print qsort([3,1,4,2,5]) == [1,2,3,4,5]
fuente
Fácil implementación a partir de algoritmos de grokking
def quicksort(arr): if len(arr) < 2: return arr #base case else: pivot = arr[0] less = [i for i in arr[1:] if i <= pivot] more = [i for i in arr[1:] if i > pivot] return quicksort(less) + [pivot] + quicksort(more)
fuente
Creo que ambas respuestas aquí funcionan bien para la lista proporcionada (que responde a la pregunta original), pero se romperían si se pasa una matriz que contenga valores no únicos. Entonces, para completar, solo señalaría el pequeño error en cada uno y explicaría cómo solucionarlo.
Por ejemplo, intentar ordenar la siguiente matriz [12,4,5,6,7,3,1,15,1] (Tenga en cuenta que 1 aparece dos veces) con el algoritmo de Brionius ... en algún momento terminará con la matriz less vacía y la matriz igual con un par de valores (1,1) que no se pueden separar en la siguiente iteración y el len ()> 1 ... por lo tanto, terminará con un bucle infinito
Puede solucionarlo devolviendo la matriz si menos está vacío o mejor no llamando a sort en su matriz igual, como en la respuesta de zangw
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) # Don't forget to return something! return sort(less)+ equal +sort(greater) # Just use the + operator to join lists # Note that you want equal ^^^^^ not pivot else: # You need to hande the part at the end of the recursion - when you only have one element in your array, just return the array. return array
La solución más elegante también se rompe, pero por una causa diferente, falta la devolución. cláusula en la línea de recursividad, lo que hará que en algún momento devuelva None e intente agregarlo a una lista ...
Para solucionarlo, solo agregue un retorno a esa línea
def qsort(arr): if len(arr) <= 1: return arr else: return qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]])
fuente
Esta es una versión de la ordenación rápida que usa el esquema de partición Hoare y con menos intercambios y variables locales
def quicksort(array): qsort(array, 0, len(array)-1) def qsort(A, lo, hi): if lo < hi: p = partition(A, lo, hi) qsort(A, lo, p) qsort(A, p + 1, hi) def partition(A, lo, hi): pivot = A[lo] i, j = lo-1, hi+1 while True: i += 1 j -= 1 while(A[i] < pivot): i+= 1 while(A[j] > pivot ): j-= 1 if i >= j: return j A[i], A[j] = A[j], A[i] test = [21, 4, 1, 3, 9, 20, 25, 6, 21, 14] print quicksort(test)
fuente
Partición : divide una matriz mediante un pivote para que los elementos más pequeños se muevan hacia la izquierda y los elementos mayores se muevan hacia la derecha o viceversa. Un pivote puede ser un elemento aleatorio de una matriz. Para hacer este algoritmo, necesitamos saber qué es el índice inicial y final de una matriz y dónde está un pivote. Luego configure dos punteros auxiliares L, R.
Entonces tenemos un usuario de matriz [..., begin, ..., end, ...]
La posición inicial de los punteros L y R
[..., begin, next, ..., end, ...]
R L
while L <end
1. Si un usuario [pivote]> usuario [L], entonces mueva R en uno e intercambie usuario [R] con usuario [L]
2. mueva L en uno
Después de while, intercambiar usuario [R] con usuario [pivote]
Clasificación rápida : use el algoritmo de partición hasta que cada parte siguiente de la división por un pivote tenga un índice inicial mayor o igual que el índice final.
def qsort(user, begin, end): if begin >= end: return # partition # pivot = begin L = begin+1 R = begin while L < end: if user[begin] > user[L]: R+=1 user[R], user[L] = user[L], user[R] L+= 1 user[R], user[begin] = user[begin], user[R] qsort(user, 0, R) qsort(user, R+1, end) tests = [ {'sample':[1],'answer':[1]}, {'sample':[3,9],'answer':[3,9]}, {'sample':[1,8,1],'answer':[1,1,8]}, {'sample':[7,5,5,1],'answer':[1,5,5,7]}, {'sample':[4,10,5,9,3],'answer':[3,4,5,9,10]}, {'sample':[6,6,3,8,7,7],'answer':[3,6,6,7,7,8]}, {'sample':[3,6,7,2,4,5,4],'answer':[2,3,4,4,5,6,7]}, {'sample':[1,5,6,1,9,0,7,4],'answer':[0,1,1,4,5,6,7,9]}, {'sample':[0,9,5,2,2,5,8,3,8],'answer':[0,2,2,3,5,5,8,8,9]}, {'sample':[2,5,3,3,2,0,9,0,0,7],'answer':[0,0,0,2,2,3,3,5,7,9]} ] for test in tests: sample = test['sample'][:] answer = test['answer'] qsort(sample,0,len(sample)) print(sample == answer)
fuente
O si prefiere un resumen que también ilustre el equivalente en Python de varags de C / C ++, expresiones lambda y expresiones if:
qsort = lambda x=None, *xs: [] if x is None else qsort(*[a for a in xs if a<x]) + [x] + qsort(*[a for a in xs if a>=x])
fuente
def quick_sort(self, nums): def helper(arr): if len(arr) <= 1: return arr #lwall is the index of the first element euqal to pivot #rwall is the index of the first element greater than pivot #so arr[lwall:rwall] is exactly the middle part equal to pivot after one round lwall, rwall, pivot = 0, 0, 0 #choose rightmost as pivot pivot = arr[-1] for i, e in enumerate(arr): if e < pivot: #when element is less than pivot, shift the whole middle part to the right by 1 arr[i], arr[lwall] = arr[lwall], arr[i] lwall += 1 arr[i], arr[rwall] = arr[rwall], arr[i] rwall += 1 elif e == pivot: #when element equals to pivot, middle part should increase by 1 arr[i], arr[rwall] = arr[rwall], arr[i] rwall += 1 elif e > pivot: continue return helper(arr[:lwall]) + arr[lwall:rwall] + helper(arr[rwall:]) return helper(nums)
fuente
Sé que muchas personas han respondido correctamente a esta pregunta y disfruté leyéndolas. Mi respuesta es casi la misma que la de zangw, pero creo que los colaboradores anteriores no hicieron un buen trabajo al explicar visualmente cómo funcionan las cosas realmente ... así que aquí está mi intento de ayudar a otros que puedan visitar esta pregunta / respuestas en el futuro sobre un solución simple para la implementación de clasificación rápida.
Como funciona ?
Aquí hay un ejemplo junto con visual para acompañarlo ... (pivote) 9,11,2,0
promedio: n logaritmo de n
peor caso: n ^ 2
El código:
def quicksort(data): if (len(data) < 2): return data else: pivot = data[0] # pivot #starting from element 1 to the end rest = data[1:] low = [each for each in rest if each < pivot] high = [each for each in rest if each >= pivot] return quicksort(low) + [pivot] + quicksort(high)
items = [9,11,2,0] print (quicksort (items))
fuente
El algoritmo contiene dos límites, uno con elementos menores que el pivote (seguido por el índice "j") y el otro con elementos mayores que el pivote (seguido por el índice "i").
En cada iteración, se procesa un nuevo elemento incrementando j.
Invariante:-
Si se viola el invariante, los elementos i y j se intercambian y se incrementa i.
Después de que se hayan procesado todos los elementos, y todo después de que se haya particionado el pivote, el elemento pivote se intercambia con el último elemento más pequeño que él.
El elemento pivote ahora estará en su lugar correcto en la secuencia. Los elementos anteriores serán menores que él y los posteriores serán mayores que él, y no estarán clasificados.
def quicksort(sequence, low, high): if low < high: pivot = partition(sequence, low, high) quicksort(sequence, low, pivot - 1) quicksort(sequence, pivot + 1, high) def partition(sequence, low, high): pivot = sequence[low] i = low + 1 for j in range(low + 1, high + 1): if sequence[j] < pivot: sequence[j], sequence[i] = sequence[i], sequence[j] i += 1 sequence[i-1], sequence[low] = sequence[low], sequence[i-1] return i - 1 def main(sequence): quicksort(sequence, 0, len(sequence) - 1) return sequence if __name__ == '__main__': sequence = [-2, 0, 32, 1, 56, 99, -4] print(main(sequence))
Seleccionar un pivote
Un pivote "bueno" dará como resultado dos subsecuencias de aproximadamente el mismo tamaño. De manera determinista, un elemento pivote puede seleccionarse de manera ingenua o calculando la mediana de la secuencia.
Una implementación ingenua de seleccionar un pivote será el primer o último elemento. El peor tiempo de ejecución en este caso será cuando la secuencia de entrada ya esté ordenada o ordenada al revés, ya que una de las subsecuencias estará vacía, lo que provocará que solo se elimine un elemento por llamada recursiva.
Se logra una división perfectamente equilibrada cuando el pivote es el elemento mediano de la secuencia. Hay un número igual de elementos mayores y menores que él. Este enfoque garantiza un mejor tiempo de funcionamiento general, pero requiere mucho más tiempo.
Una forma no determinista / aleatoria de seleccionar el pivote sería elegir un elemento uniformemente al azar. Este es un enfoque simple y ligero que minimizará el peor de los casos y también conducirá a una división más o menos equilibrada. Esto también proporcionará un equilibrio entre el enfoque ingenuo y el enfoque medio de seleccionar el pivote.
fuente
def quicksort(array): if len(array) < 2: return array else: pivot = array[0] less = [i for i in array[1:] if i <= pivot] greater = [i for i in array[1:] if i > pivot] return quicksort(less) + [pivot] + quicksort(greater)
fuente
def quick_sort(array): return quick_sort([x for x in array[1:] if x < array[0]]) + [array[0]] \ + quick_sort([x for x in array[1:] if x >= array[0]]) if array else []
fuente
def Partition(A,p,q): i=p x=A[i] for j in range(p+1,q+1): if A[j]<=x: i=i+1 tmp=A[j] A[j]=A[i] A[i]=tmp l=A[p] A[p]=A[i] A[i]=l return i def quickSort(A,p,q): if p<q: r=Partition(A,p,q) quickSort(A,p,r-1) quickSort(A,r+1,q) return A
fuente
Una implementación "verdadera" en el lugar [Algoritmos 8.9, 8.11 del Libro de Aplicaciones y Diseño de Algoritmos de Michael T. Goodrich y Roberto Tamassia]:
from random import randint def partition (A, a, b): p = randint(a,b) # or mid point # p = (a + b) / 2 piv = A[p] # swap the pivot with the end of the array A[p] = A[b] A[b] = piv i = a # left index (right movement ->) j = b - 1 # right index (left movement <-) while i <= j: # move right if smaller/eq than/to piv while A[i] <= piv and i <= j: i += 1 # move left if greater/eq than/to piv while A[j] >= piv and j >= i: j -= 1 # indices stopped moving: if i < j: # swap t = A[i] A[i] = A[j] A[j] = t # place pivot back in the right place # all values < pivot are to its left and # all values > pivot are to its right A[b] = A[i] A[i] = piv return i def IpQuickSort (A, a, b): while a < b: p = partition(A, a, b) # p is pivot's location #sort the smaller partition if p - a < b - p: IpQuickSort(A,a,p-1) a = p + 1 # partition less than p is sorted else: IpQuickSort(A,p+1,b) b = p - 1 # partition greater than p is sorted def main(): A = [12,3,5,4,7,3,1,3] print A IpQuickSort(A,0,len(A)-1) print A if __name__ == "__main__": main()
fuente
El algoritmo consta de 4 sencillos pasos:
Código para el algoritmo en python:
def my_sort(A): p=A[0] #determine pivot element. left=[] #create left array right=[] #create right array for i in range(1,len(A)): #if cur elem is less than pivot, add elem in left array if A[i]< p: left.append(A[i]) #the recurssion will occur only if the left array is atleast half the size of original array if len(left)>1 and len(left)>=len(A)//2: left=my_sort(left) #recursive call elif A[i]>p: right.append(A[i]) #if elem is greater than pivot, append it to right array if len(right)>1 and len(right)>=len(A)//2: # recurssion will occur only if length of right array is atleast the size of original array right=my_sort(right) A=left+[p]+right #append all three part of the array into one and return it return A my_sort([12,4,5,6,7,3,1,15])
Continúe con este algoritmo de forma recursiva con las partes izquierda y derecha.
fuente
Otra implementación de clasificación rápida:
# A = Array # s = start index # e = end index # p = pivot index # g = greater than pivot boundary index def swap(A,i1,i2): A[i1], A[i2] = A[i2], A[i1] def partition(A,g,p): # O(n) - just one for loop that visits each element once for j in range(g,p): if A[j] <= A[p]: swap(A,j,g) g += 1 swap(A,p,g) return g def _quicksort(A,s,e): # Base case - we are sorting an array of size 1 if s >= e: return # Partition current array p = partition(A,s,e) _quicksort(A,s,p-1) # Left side of pivot _quicksort(A,p+1,e) # Right side of pivot # Wrapper function for the recursive one def quicksort(A): _quicksort(A,0,len(A)-1) A = [3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,-1] print(A) quicksort(A) print(A)
fuente
Para la versión Python 3.x : un
operator
módulo de uso de estilo funcional , principalmente para mejorar la legibilidad.from operator import ge as greater, lt as lesser def qsort(L): if len(L) <= 1: return L pivot = L[0] sublist = lambda op: [*filter(lambda num: op(num, pivot), L[1:])] return qsort(sublist(lesser))+ [pivot] + qsort(sublist(greater))
y se prueba como
print (qsort([3,1,4,2,5]) == [1,2,3,4,5])
fuente
… complete my code?
. Usarlambda
para definirsublist()
no parece estrictamente necesario.sublist
puede definir solo usandofilter
? ¿Es eso siquiera posible?def
- no empecé a retocar todavía, ya que estoy tratando de averiguar si hay una forma más eficiente de "distribuir" los elementos de un iterable en listas separadas (o, alternativamente, una lista con una " categoría "después de la otra).)Aquí hay una implementación fácil: -
def quicksort(array): if len(array) < 2: return array else: pivot= array[0] less = [i for i in array[1:] if i <= pivot] greater = [i for i in array[1:] if i > pivot] return quicksort(less) + [pivot] + quicksort(greater) print(quicksort([10, 5, 2, 3]))
fuente
¡Adjunto el código a continuación! Esta clasificación rápida es una gran herramienta de aprendizaje debido a la ubicación del valor de pivote . Dado que está en un lugar constante, puede recorrerlo varias veces y comprender realmente cómo funciona todo. En la práctica, es mejor aleatorizar el pivote para evitar el tiempo de ejecución O (N ^ 2).
def quicksort10(alist): quicksort_helper10(alist, 0, len(alist)-1) def quicksort_helper10(alist, first, last): """ """ if first < last: split_point = partition10(alist, first, last) quicksort_helper10(alist, first, split_point - 1) quicksort_helper10(alist, split_point + 1, last) def partition10(alist, first, last): done = False pivot_value = alist[first] leftmark = first + 1 rightmark = last while not done: while leftmark <= rightmark and alist[leftmark] <= pivot_value: leftmark = leftmark + 1 while leftmark <= rightmark and alist[rightmark] >= pivot_value: rightmark = rightmark - 1 if leftmark > rightmark: done = True else: temp = alist[leftmark] alist[leftmark] = alist[rightmark] alist[rightmark] = temp temp = alist[first] alist[first] = alist[rightmark] alist[rightmark] = temp return rightmark
fuente
def quick_sort(l): if len(l) == 0: return l pivot = l[0] pivots = [x for x in l if x == pivot] smaller = quick_sort([x for x in l if x < pivot]) larger = quick_sort([x for x in l if x > pivot]) return smaller + pivots + larger
fuente
Ejemplo completo con variables impresas en el paso de partición:
def partition(data, p, right): print("\n==> Enter partition: p={}, right={}".format(p, right)) pivot = data[right] print("pivot = data[{}] = {}".format(right, pivot)) i = p - 1 # this is a dangerous line for j in range(p, right): print("j: {}".format(j)) if data[j] <= pivot: i = i + 1 print("new i: {}".format(i)) print("swap: {} <-> {}".format(data[i], data[j])) data[i], data[j] = data[j], data[i] print("swap2: {} <-> {}".format(data[i + 1], data[right])) data[i + 1], data[right] = data[right], data[i + 1] return i + 1 def quick_sort(data, left, right): if left < right: pivot = partition(data, left, right) quick_sort(data, left, pivot - 1) quick_sort(data, pivot + 1, right) data = [2, 8, 7, 1, 3, 5, 6, 4] print("Input array: {}".format(data)) quick_sort(data, 0, len(data) - 1) print("Output array: {}".format(data))
fuente
def is_sorted(arr): #check if array is sorted for i in range(len(arr) - 2): if arr[i] > arr[i + 1]: return False return True def qsort_in_place(arr, left, right): #arr - given array, #left - first element index, #right - last element index if right - left < 1: #if we have empty or one element array - nothing to do return else: left_point = left #set left pointer that points on element that is candidate to swap with element under right pointer or pivot element right_point = right - 1 #set right pointer that is candidate to swap with element under left pointer while left_point <= right_point: #while we have not checked all elements in the given array swap_left = arr[left_point] >= arr[right] #True if we have to move that element after pivot swap_right = arr[right_point] < arr[right] #True if we have to move that element before pivot if swap_left and swap_right: #if both True we can swap elements under left and right pointers arr[right_point], arr[left_point] = arr[left_point], arr[right_point] left_point += 1 right_point -= 1 else: #if only one True we don`t have place for to swap it if not swap_left: #if we dont need to swap it we move to next element left_point += 1 if not swap_right: #if we dont need to swap it we move to prev element right_point -= 1 arr[left_point], arr[right] = arr[right], arr[left_point] #swap left element with pivot qsort_in_place(arr, left, left_point - 1) #execute qsort for left part of array (elements less than pivot) qsort_in_place(arr, left_point + 1, right) #execute qsort for right part of array (elements most than pivot) def main(): import random arr = random.sample(range(1, 4000), 10) #generate random array print(arr) print(is_sorted(arr)) qsort_in_place(arr, 0, len(arr) - 1) print(arr) print(is_sorted(arr)) if __name__ == "__main__": main()
fuente
Este algoritmo no usa funciones recursivas.
Sea
N
cualquier lista de números conlen(N) > 0
. ConfigureK = [N]
y ejecute el siguiente programa.Nota: este es un algoritmo de clasificación estable .
def BinaryRip2Singletons(K, S): K_L = [] K_P = [ [K[0][0]] ] K_R = [] for i in range(1, len(K[0])): if K[0][i] < K[0][0]: K_L.append(K[0][i]) elif K[0][i] > K[0][0]: K_R.append(K[0][i]) else: K_P.append( [K[0][i]] ) K_new = [K_L]*bool(len(K_L)) + K_P + [K_R]*bool(len(K_R)) + K[1:] while len(K_new) > 0: if len(K_new[0]) == 1: S.append(K_new[0][0]) K_new = K_new[1:] else: break return K_new, S N = [16, 19, 11, 15, 16, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1] K = [ N ] S = [] print('K =', K, 'S =', S) while len(K) > 0: K, S = BinaryRip2Singletons(K, S) print('K =', K, 'S =', S)
K = [[16, 19, 11, 15, 16, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1]] S = [] K = [[11, 15, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1], [16], [16], [19]] S = [] K = [[10, 4, 10, 5, 2, 3, 4, 7, 1], [11], [15, 12, 14], [16], [16], [19]] S = [] K = [[4, 5, 2, 3, 4, 7, 1], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = [] K = [[2, 3, 1], [4], [4], [5, 7], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = [] K = [[5, 7], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = [1, 2, 3, 4, 4] K = [[15, 12, 14], [16], [16], [19]] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11] K = [[12, 14], [15], [16], [16], [19]] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11] K = [] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11, 12, 14, 15, 16, 16, 19]
fuente
Probablemente solo sea una cuestión de preferencia, pero me gusta agregar validación a la parte superior de mis funciones.
def quicksort(arr): if len(arr) <= 1: return arr left = [] right = [] equal = [] pivot = arr[-1] for num in arr: if num < pivot: left.append(num) elif num == pivot: equal.append(num) else: right.append(num) return quicksort(left) + equal + quicksort(right)
fuente