Algoritmo Quicksort en Python para Ordenar Playlists por BPM y Energía
Clasificado en Inglés
Escrito el en
español con un tamaño de 6,14 KB
Algoritmos de Ordenamiento Quicksort para Listas de Reproducción
A continuación se presentan diferentes variantes e implementaciones del algoritmo Quicksort en Python, diseñadas para ordenar listas de canciones (tracks) considerando el flujo musical mediante el tempo (BPM) de forma ascendente y la energía de forma descendente.
Implementación 1: Partición de Lomuto con Copia Segura de Lista
Esta variante utiliza el esquema clásico de partición de Lomuto y genera una copia defensiva del arreglo para preservar los datos de la lista original intactos.
def sort_playlist_by_flow(tracks, use_energy):
# Comparador del DJ (devuelve True si a < b)
def less(a, b):
bpm_a = a[1]
bpm_b = b[1]
if bpm_a != bpm_b:
return bpm_a < bpm_b
if use_energy:
energy_a = a[2]
energy_b = b[2]
if energy_a != energy_b:
return energy_a > energy_b # energy descendente
return False # considera iguales → no mover
def partition(arr, left, right):
pivot = arr[right] # pivote = último elemento
i = left - 1 # índice del menor
for j in range(left, right):
if less(arr[j], pivot): # arr[j] < pivot
i += 1
arr[i], arr[j] = arr[j], arr[i] # swap
# colocar pivote en su posición final
arr[i+1], arr[right] = arr[right], arr[i+1]
return i + 1
def quicksort(arr, left, right):
if left < right:
p = partition(arr, left, right)
quicksort(arr, left, p - 1)
quicksort(arr, p + 1, right)
arr = tracks[:] # copiar para no modificar el original
quicksort(arr, 0, len(arr)-1)
# devolver solo títulos
return [t[0] for t in arr]Implementación 2: Partición Bidireccional In-Place con Validación de Atributos
Esta solución aplica una partición bidireccional (estilo Hoare) directamente sobre la lista pasada por parámetro, comprobando la longitud de los registros para evitar errores si la propiedad de energía no está presente.
def sort_playlist_by_flow(tracks, use_energy):
def comparar_dj_simple(a, b):
bpm_a = a[1]
bpm_b = b[1]
if bpm_a != bpm_b:
return bpm_a < bpm_b
if use_energy:
energy_a = a[2] if len(a) > 2 else 0
energy_b = b[2] if len(b) > 2 else 0
if energy_a != energy_b:
return energy_a > energy_b
return False
def partition(arr, left, right):
pivot = arr[right]
i = left
j = right - 1
while True:
while i <= j and comparar_dj_simple(arr[i], pivot):
i += 1
while i <= j and comparar_dj_simple(pivot, arr[j]):
j -= 1
if i >= j:
break
arr[i], arr[j] = arr[j], arr[i]
i += 1
j -= 1
arr[i], arr[right] = arr[right], arr[i]
return i
def quicksort_recursivo(arr, left, right):
if left < right:
p = partition(arr, left, right)
quicksort_recursivo(arr, left, p - 1)
quicksort_recursivo(arr, p + 1, right)
if not tracks:
return []
quicksort_recursivo(tracks, 0, len(tracks) - 1)
return [t[0] for t in tracks]Implementación 3: Réplica de Partición Bidireccional
Segunda instancia del método in-place bidireccional con validación de elementos nulos y control de longitud por tupla.
def sort_playlist_by_flow(tracks, use_energy):
def comparar_dj_simple(a, b):
bpm_a = a[1]
bpm_b = b[1]
if bpm_a != bpm_b:
return bpm_a < bpm_b
if use_energy:
energy_a = a[2] if len(a) > 2 else 0
energy_b = b[2] if len(b) > 2 else 0
if energy_a != energy_b:
return energy_a > energy_b
return False
def partition(arr, left, right):
pivot = arr[right]
i = left
j = right - 1
while True:
while i <= j and comparar_dj_simple(arr[i], pivot):
i += 1
while i <= j and comparar_dj_simple(pivot, arr[j]):
j -= 1
if i >= j:
break
arr[i], arr[j] = arr[j], arr[i]
i += 1
j -= 1
arr[i], arr[right] = arr[right], arr[i]
return i
def quicksort_recursivo(arr, left, right):
if left < right:
p = partition(arr, left, right)
quicksort_recursivo(arr, left, p - 1)
quicksort_recursivo(arr, p + 1, right)
if not tracks:
return []
quicksort_recursivo(tracks, 0, len(tracks) - 1)
return [t[0] for t in tracks]Implementación 4: Esquema Compacto de Lomuto con Copia de Seguridad
Variación simplificada de la ordenación por Lomuto preservando inmutabilidad en la entrada original.
def sort_playlist_by_flow(tracks, use_energy):
def less(a, b):
bpm_a = a[1]
bpm_b = b[1]
if bpm_a != bpm_b:
return bpm_a < bpm_b
if use_energy:
energy_a = a[2]
energy_b = b[2]
if energy_a != energy_b:
return energy_a > energy_b
return False # considera iguales → no mover
def partition(arr, left, right):
pivot = arr[right] # pivote = último elemento
i = left - 1 # índice del menor
for j in range(left, right):
if less(arr[j], pivot): # arr[j] < pivot
i += 1
arr[i], arr[j] = arr[j], arr[i] # swap
arr[i+1], arr[right] = arr[right], arr[i+1]
return i + 1
def quicksort(arr, left, right):
if left < right:
p = partition(arr, left, right)
quicksort(arr, left, p - 1)
quicksort(arr, p + 1, right)
arr = tracks[:] # copiar para no modificar el original
quicksort(arr, 0, len(arr)-1)
return [t[0] for t in arr]