Python - Ordenar arreglo con merge sort

Python: ordenar lista con merge sort

Hoy vamos a ver cómo implementar el ordenamiento por mezcla o merge sort en Python. Básicamente este algoritmo nos va a servir para ordenar un arreglo de cualquier tipo (suponiendo que los valores son comparables).

Hay varios enfoques para este algoritmo; algunos usan una función y otros usan 2. Yo usaré éste último enfoque pues todo queda más claro.

Por cierto, también usaremos la recursividad, ya que es un aspecto clave al momento de ordenar un array con merge sort en Python.

Explicación del algoritmo

Para el ordenamiento por mezcla necesitamos dividir el arreglo en 2, y luego esas 2 partes dividirlas de nuevo en 2. Así hasta tener un par de arreglos de longitud 1 o 0.

Eso que expliqué anteriormente usará la recursividad, ya que la función se va a seguir invocando hasta que la condición de salida se cumpla. Y para este punto ya tendremos un arreglo de 1 o 0.

Ahora viene la segunda parte. Cuando ya tenemos los dos arreglos, los recorremos a ambos con dos índices y vamos agregando el valor menor a un nuevo arreglo, mismo que ya va a estar ordenado.

Cuando ya esté ordenado, lo regresamos. Y este paso se va a repetir por cada par de arreglos. Al final, después de ordenar todas las mitades, el arreglo estará ordenado.

Merge sort en Python

Veamos entonces la primera función. La misma podría llamarse simplemente “dividir” pero la he llamado “merge_sort” para que el nombre tenga sentido al invocarla:

def merge_sort(arreglo):
    longitud = len(arreglo)
    mitad = longitud//2  # El doble / es para dividir y redondear hacia abajo
    # Condición de salida de recursividad es que el arreglo mida 1 o 0
    if longitud <= 1:
        return arreglo
    mitad_izquierda = arreglo[:mitad]
    mitad_derecha = arreglo[mitad:]
    mitad_izquierda = merge_sort(mitad_izquierda)
    mitad_derecha = merge_sort(mitad_derecha)
    return merge(mitad_izquierda, mitad_derecha)

En la línea 2 calculamos la longitud del arreglo, ya que vamos a dividirlo según la misma. Luego en la línea 5 tenemos la condición de salida, que es en donde la recursión termina.

Si el arreglo no mide 1 o menos de 1, entonces lo dividimos en dos partes usando operaciones de listas con Python en las líneas 7 y 8.

La recursión está en la línea 9 y 10, que es en donde invocamos a la función dentro de sí misma. Y finalmente en la línea 11 regresamos lo que devuelva merge, que va a combinar el arreglo.

Función merge para ordenar arreglo en Python

Ahora veamos la otra función que va a ordenar ambos arreglos y combinarlos en uno solo.

Aquí es en donde realmente se hace el ordenamiento por merge sort, pues recibimos ambas mitades y las ordenamos en un nuevo arreglo.

def merge(izquierda, derecha):
    print(f"Recibo {izquierda} y {derecha}")
    arreglo_ordenado = []
    indice_de_izquierda = 0
    indice_de_derecha = 0
    indice_arreglo_ordenado = 0
    # Recorremos ambos arreglos y vamos colocando los elementos ordenados. Colocamos siempre el que sea menor
    while indice_de_izquierda < len(izquierda) and indice_de_derecha < len(derecha):
        valor_izquierda = izquierda[indice_de_izquierda]
        valor_derecha = derecha[indice_de_derecha]
        if valor_izquierda <= valor_derecha:
            # El de la izquierda es menor, entonces lo ponemos primero
            arreglo_ordenado.append(valor_izquierda)
            # Y aumentamos en 1 el valor de la izquierda
            indice_de_izquierda += 1
        else:
            arreglo_ordenado.append(valor_derecha)
            indice_de_derecha += 1

        # Sin importar lo que hayamos movido, aumentamos el índice del actual
        indice_arreglo_ordenado += 1
    # Hasta aquí puede que el índice izquierdo o derecho hayan llegado a su fin, pero no ambos. Entonces
    # nos aseguramos de recorrerlos a ambos hasta el final
    while indice_de_izquierda < len(izquierda):
        arreglo_ordenado.append(izquierda[indice_de_izquierda])
        indice_de_izquierda += 1

    while indice_de_derecha < len(derecha):
        arreglo_ordenado.append(derecha[indice_de_derecha])
        indice_de_derecha += 1
    print(f"Los ordeno y combino. Resultado: {arreglo_ordenado}.")
    return arreglo_ordenado

En la línea 3 iniciamos el arreglo que ya estará ordenado. Aquí vamos a combinar ambas mitades, y al combinarlas vamos a ordenarlas.

Luego en la línea 4, 5 y 6 declaramos los índices.

Por cierto, el índice del arreglo ordenado no importa ya que vamos a usar append y simplemente agregaremos elementos al arreglo ordenado; si estuviéramos en otro lenguaje tal vez sí lo usaríamos.

Luego recorremos ambas mitades en la línea 8, y comparamos en la 11 y dependiendo del arreglo del cual hayamos tomado el elemento aumentamos su índice correspondiente.

Al llenar a la línea 28 puede que hayamos llegado al final de alguna de las mitades, pero no de ambas; entonces simplemente agregamos los elementos restantes de ambas a la lista ordenada.

Finalmente regresamos el arreglo ordenado. Y así tenemos el merge sort aplicado a una lista de Python.

Nota: yo estoy imprimiendo información para que el algoritmo sea más explicativo, tú puedes remover esas líneas sin problema.

Poniendo todo junto

Ahora veamos el código de ambas funciones y el modo de uso. Ya te dije anteriormente que se puede usar un arreglo de cualquier tipo; solo debes hacer la comparación necesaria. El código queda así:

"""
    https://parzibyte.me/blog
"""
def merge_sort(arreglo):
    longitud = len(arreglo)
    mitad = longitud//2  # El doble / es para dividir y redondear hacia abajo
    # Condición de salida de recursividad es que el arreglo mida 1 o 0
    if longitud <= 1:
        return arreglo
    mitad_izquierda = arreglo[:mitad]
    mitad_derecha = arreglo[mitad:]
    mitad_izquierda = merge_sort(mitad_izquierda)
    mitad_derecha = merge_sort(mitad_derecha)
    return merge(mitad_izquierda, mitad_derecha)


def merge(izquierda, derecha):
    print(f"Recibo {izquierda} y {derecha}")
    arreglo_ordenado = []
    indice_de_izquierda = 0
    indice_de_derecha = 0
    indice_arreglo_ordenado = 0
    # Recorremos ambos arreglos y vamos colocando los elementos ordenados. Colocamos siempre el que sea menor
    while indice_de_izquierda < len(izquierda) and indice_de_derecha < len(derecha):
        valor_izquierda = izquierda[indice_de_izquierda]
        valor_derecha = derecha[indice_de_derecha]
        if valor_izquierda <= valor_derecha:
            # El de la izquierda es menor, entonces lo ponemos primero
            arreglo_ordenado.append(valor_izquierda)
            # Y aumentamos en 1 el valor de la izquierda
            indice_de_izquierda += 1
        else:
            arreglo_ordenado.append(valor_derecha)
            indice_de_derecha += 1

        # Sin importar lo que hayamos movido, aumentamos el índice del actual
        indice_arreglo_ordenado += 1
    # Hasta aquí puede que el índice izquierdo o derecho hayan llegado a su fin, pero no ambos. Entonces
    # nos aseguramos de recorrerlos a ambos hasta el final
    while indice_de_izquierda < len(izquierda):
        arreglo_ordenado.append(izquierda[indice_de_izquierda])
        indice_de_izquierda += 1

    while indice_de_derecha < len(derecha):
        arreglo_ordenado.append(derecha[indice_de_derecha])
        indice_de_derecha += 1
    print(f"Los ordeno y combino. Resultado: {arreglo_ordenado}.")
    return arreglo_ordenado


arreglo = [6, 5, 3, 1, 8, 7, 2, 4]
print(f"Arreglo original: {arreglo}")
print("Ordenando con merge sort y recursividad...")
arreglo_ordenado = merge_sort(arreglo)
print(f"Arreglo ordenado: {arreglo_ordenado}")

Al ejecutarlo, la salida es correcta:

Python - Ordenar arreglo con merge sort
Python – Ordenar arreglo con merge sort

Además, se está imprimiendo información para que veas cómo se separa y ordena el arreglo. Por cierto, el mismo es el que aparece como ejemplo en la Wikipedia.

Para terminar te dejo con otros algoritmos de ordenamiento y más tutoriales de Python.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

1 comentario en “Python: ordenar lista con merge sort”

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *