Quicksort que devuelve el pedido incorrecto
Estoy trabajando en una implementación de quicksort en Python con recursividad sin crear nuevas variables para contener las partes izquierda y derecha de la matriz particionada.
Obtengo valores incorrectos al ejecutar el paso recursivo. Esto es lo que he hecho hasta ahora:
def swap(a,i,j):
tmp = a[i]
a[i] = a[j]
a[j] = tmp
def pivot(a, lo, hi):
mid = (lo + hi) // 2
# sort lo, mid, hi:
if a[mid] < a[lo]:
swap(a, lo, mid)
if a[hi] < a[lo]:
swap(a, lo, hi)
if a[hi] < a[mid]:
swap(a, mid, hi)
def partition(a, lo, hi):
# place the pivot out of the way, in position hi -1
mid = (lo + hi)//2
swap(a, mid, hi - 1)
i = lo
j = hi - 1
pivot = a[j]
while True:
while True:
i += 1
if a[i] >= pivot: break
while True:
j -= 1
if a[j] <= pivot: break
if i >= j: break
swap(a, i, j)
swap(a, i, hi - 1)
return i
Suponiendo que el código de plantilla anterior es "correcto". Tuve que implementar la clasificación rápida usando las implementaciones anteriores de pivote y partición. Esto es lo que hice:
def quicksort(a):
_sort(a, 0, len(a)-1)
def _sort(a, left, right):
if(left < right):
pivot(a, left, right)
piv = partition(a, left, right)
_sort(a, left, piv-1)
_sort(a, piv+1, right)
Cuando llamo a la clasificación rápida con una lista:
x = [98, 33, 11, 5, 1, 10, 11, 12, 14, 33, 55, 66, 556, 88]
quicksort(x)
print(x)
>>> [1, 5, 10, 11, 11, 12, 14, 33, 33, 55, 66, 88, 556, 98]
Puede ver que el 98 está fuera de lugar. Si corro así:
x = [9, 7, 5, 11, 12, 2, 14, 3, 10, 6, 55, 66, 888, 33, 556, 10]
quicksort(x)
print(x)
>>> [2, 3, 5, 6, 7, 9, 10, 10, 11, 12, 14, 33, 55, 66, 556, 888]
Entonces, para el caso anterior es correcto. Pero en otros casos más pequeños falla:
x = [98, 33, 11, 556, 88]
quicksort(x)
print(x)
>>> [33, 11, 88, 556, 98]
¿Alguien puede ayudarme a encontrar el error? Gracias :-)
Respuestas
Veo dos errores, el primero está en tu partition()función.
Intente sustituir swap(a, i, hi - 1)conswap(a, i, hi)
El segundo está en _sort(). La última llamada debería ser_sort(a, piv, right)
El código correcto es:
def partition(a, lo, hi):
# place the pivot out of the way, in position hi -1
mid = (lo + hi)//2
swap(a, mid, hi - 1)
i = lo
j = hi - 1
pivot = a[j]
while True:
while True:
i += 1
if a[i] >= pivot: break
while True:
j -= 1
if a[j] <= pivot: break
if i >= j: break
swap(a, i, j)
swap(a, i, hi)
return i
y
def _sort(a, left, right):
if(left < right):
pivot(a, left, right)
piv = partition(a, left, right)
_sort(a, left, piv-1)
_sort(a, piv, right)
Prueba:
x = [98, 33, 11, 556, 88]
quicksort(x)
print(x)
[11, 33, 88, 98, 556]
Algunas pruebas más:
import random
for n in range(10):
x = [random.randint(1,999) for i in range(random.randint(4,10))]
quicksort(x)
print(x)
[104, 226, 721, 769]
[131, 453, 590, 730, 752, 834]
[132, 156, 191, 277, 541, 599, 666, 909, 919]
[114, 210, 280, 919, 968, 978]
[127, 212, 381, 458, 585, 594, 685, 809, 935]
[73, 90, 189, 591, 599, 686, 806, 829, 831, 906]
[89, 115, 208, 601, 774, 813, 842, 981]
[159, 177, 203, 231, 621, 759, 950]
[347, 348, 417, 476, 850, 902]
[8, 50, 51, 483, 499, 696, 842]