Algoritmos de Programación con Python

19.1. Ordenamiento por selección

Éste método de ordenamiento se basa en la siguiente idea:

Paso 1.1: Buscar el mayor de todos los elementos de la lista.

Lista = | 3 | 2 | -1 | 5 | 0 | 2 |

Encuentra el valor 5 en la posición 3.

Paso 1.2: Poner el mayor al final (intercambiar el que está en la última posición de la lista con el mayor encontrado).

Intercambia el elemento de la posición 3 con el de la posición 5. En la última posición de la lista está el mayor de todos.

Lista = | 3 | 2 | -1 | 2 | 0 | 5 |

Paso 2.1: Buscar el mayor de todos los elementos del segmento de la lista entre la primera y la anteúltima posición.

Lista = | 3 | 2 | -1 | 2 | 0 | 5 |

Encuentra el valor 3 en la posición 0.

Paso 2.2: Poner el mayor al final del segmento (intercambiar el que está en la última posición del segmento, o sea anteúltima posición de la lista, con el mayor encontrado).

Lista = | 0 | 2 | -1 | 2 | 3 | 5 |

Intercambia el elemento de la posición 0 con el valor de la posición 4. En la anteúltima y última posición de la lista están los dos mayores en su posición definitiva.

Paso n: Se termina cuando queda un único elemento sin tratar: el que está en la primera posición de la lista, y que es el menor de todos porque todos los mayores fueron reubicados.

Lista = | -1 | 0 | 2 | 2 | 3 | 5 |

La implementación en Python puede verse en el código 19.1.

La función principal, ord_seleccion es la encargada de recorrer la lista, ubicando el mayor elemento al final del segmento y luego reduciendo el segmento a analizar.

Mientras que buscar_max es una función que ya se estudió previamente, que busca el mayor elemento de la lista y devuelve su posición.

A continuación, algunas una ejecuciones de prueba de ese código:

>>> l=[3, 2, -1, 5, 0, 2]
>>> ord_seleccion(l)
DEBUG: 3 5 [3, 2, -1, 2, 0, 5]
DEBUG: 0 4 [0, 2, -1, 2, 3, 5]
DEBUG: 1 3 [0, 2, -1, 2, 3, 5]
DEBUG: 1 2 [0, -1, 2, 2, 3, 5]
DEBUG: 0 1 [-1, 0, 2, 2, 3, 5]
> >>> print l
[-1, 0, 2, 2, 3, 5]
>>> l=[]
>>> ord_seleccion(l)
>>> l=[1]
>>> ord_seleccion(l)
>>> print l
[1]
>>> l=[1,2,3,4,5]
>>> ord_seleccion(l)
DEBUG: 4 4 [1, 2, 3, 4, 5]
DEBUG: 3 3 [1, 2, 3, 4, 5]
DEBUG: 2 2 [1, 2, 3, 4, 5]
DEBUG: 1 1 [1, 2, 3, 4, 5]

Puede verse que aún cuando la lista está ordenada, se la recorre buscando los mayores elementos y ubicándolos en la misma posición en la que se encuentran.

19.1.1. Invariante en el ordenamiento por selección

Todo ordenamiento tiene un invariante que permite asegurarse de que cada paso que se toma va en la dirección de obtener una lista ordenada.

# Código 19.1: seleccion.py: Ordena una lista por selección

#/usr/bin/env python
#encoding: latin1

def ord_seleccion(lista):
    """ Ordena una lista de elementos según el método de selección.
        Pre: los elementos de la lista deben ser comparables.
        Post: la lista está ordenada. """

    # n = posicion final del segmento a tratar, comienza en len(lista)-1*
    n = len(lista)-1

    # cicla mientras haya elementos para ordenar (2 o más elementos)
    while n > 0:
        # p es la posicion del mayor valor del segmento
        p = buscar_max(lista, 0, n)

        # intercambia el valor que está en p con el valor que
        # está en la última posición del segmento
        lista[p], lista[n] = lista[n], lista[p]

        print "DEBUG: ", p, n, lista

        # reduce el segmento en 1
        n = n - 1

def buscar_max(lista, ini, fin):
    """ Devuelve la posición del máximo elemento en un segmento de
        lista de elementos comparables.
        Se trabaja sobre lista, que no debe ser vacía.
        ini es la posición inicial del segmento, debe ser válida.
        fin es la posición final del segmento, debe ser válida. """

    pos_max = ini
    for i in xrange(ini+1, fin+1):
        if lista[i] > lista[pos_max]:
            pos_max = i
    return pos_max

En el caso del ordenamiento por selección, el invariante es que los elementos desde n+1 hasta el final de la lista están ordenados y son mayores que los elementos de 0 a n, es decir que ya están en su posición definitiva.

19.1.2. ¿Cuánto cuesta ordenar por selección?

Como se puede ver en el código de la función buscar_max, para buscar el máximo ele-mento en un segmento de lista se debe recorrer todo ese segmento, por lo que en nuestro caso debemos recorrer en el primer paso N elementos, en el segundo paso N —1 elementos, en el tercer paso N — 2 elementos, etc. Cada visita a un elemento implica una cantidad constante y pequeña de comparaciones (que no depende de N). Por lo tanto tenemos que

T(N) = c * (2 + 3 + . . . + N ) = c * N * (N + 1)/2 = N^2

O sea que ordenar por selección una lista de tamaño N insume tiempo del orden de N^2. Como ya se vio, este tiempo es independiente de si la lista estaba previamente ordenda o no.

En cuanto al espacio utilizado, sólo se tiene en memoria la lista que se desea ordenar y algunas variables de tamaño 1.


Copyright (c) 2011-2014 Rosita Wachenchauzer, Margarita Manterola, Maximiliano Curia, Marcos Medrano, Nicolás Paez. La copia y redistribución de esta página se permite bajo los términos de la licencia Creative Commons Atribución - Compartir Obras Derivadas Igual 3.0 siempre que se conserve esta nota de copyright.