cv.cm

Programación · Algoritmos

Insertion sort (ordenamiento por inserción): cómo funciona, código y complejidad

5 min de lectura

Respuesta corta

Insertion sort construye el resultado ordenado un elemento cada vez. Toma el siguiente elemento, desplaza una posición a la derecha todos los elementos mayores de la parte ordenada y coloca el elemento en el hueco, igual que mucha gente ordena las cartas que tiene en la mano. Es O(n²) en el caso promedio y en el peor, O(n) con una entrada ya ordenada o casi ordenada, usa O(1) de espacio extra y es estable. Es el ordenamiento simple más rápido para arreglos pequeños o casi ordenados, por eso lo usan algoritmos híbridos como Timsort.

Abrir Ordenar líneas

La idea en palabras sencillas

Considera el primer elemento como una lista ordenada de longitud uno. Toma el segundo elemento e insértalo antes o después del primero. Toma el tercero e insértalo en el lugar correcto entre los dos primeros. Continúa hasta que todos los elementos hayan sido insertados.

Para insertar, aparta el nuevo elemento (llámalo key) y recorre hacia la izquierda la parte ordenada. Cada elemento mayor que key se mueve una posición a la derecha. Cuando llegues a un elemento que no sea mayor, o al inicio de la lista, coloca key en el hueco vacío.

Ejemplo resuelto, paso a paso

Ordena [12, 11, 13, 5, 6]. La parte anterior a la barra está ordenada (pero aún no es definitiva).

PasokeyDesplazamientosLista tras el paso
11112 se mueve a la derecha[11, 12 | 13, 5, 6]
213ninguno, 12 es menor[11, 12, 13 | 5, 6]
3513, 12 y 11 se mueven a la derecha[5, 11, 12, 13 | 6]
4613, 12 y 11 se mueven a la derecha[5, 6, 11, 12, 13]

Fíjate en el paso 2: un elemento que ya está en su sitio cuesta una sola comparación. Por eso insertion sort es rápido con entradas casi ordenadas.

Implementación en Python

def insertion_sort(items):
    """Sort a list in place, ascending. Returns the same list."""
    for i in range(1, len(items)):
        key = items[i]
        j = i - 1
        while j >= 0 and items[j] > key:   # strict >, keeps it stable
            items[j + 1] = items[j]        # shift right
            j -= 1
        items[j + 1] = key                 # drop into the gap
    return items
print(insertion_sort([12, 11, 13, 5, 6]))   # [5, 6, 11, 12, 13]
print(insertion_sort([1, 2, 3, 4]))         # [1, 2, 3, 4], 3 comparisons

Desplazar en lugar de intercambiar escribe cada elemento movido una sola vez, lo que supone aproximadamente la mitad del trabajo de la versión basada en intercambios. También puedes encontrar el punto de inserción con búsqueda binaria, como abajo. Esto reduce las comparaciones a O(n log n) en total, pero los desplazamientos siguen siendo O(n²), así que el tiempo global sigue siendo O(n²).

from bisect import insort_right
def binary_insertion_sort(items):
    result = []
    for x in items:
        insort_right(result, x)   # stable: equal items go after
    return result
print(binary_insertion_sort([3, 1, 2, 1]))   # [1, 1, 2, 3]

Complejidad temporal y espacial

CasoTiempoMotivo
Mejor (ya ordenada)O(n)cada elemento necesita una comparación y ningún desplazamiento
Promedio (orden aleatorio)O(n²)unos n²/4 desplazamientos en promedio
Peor (orden inverso)O(n²)el elemento i se desplaza más allá de los i elementos anteriores
Espacio extraO(1)ordena in situ con un valor temporal

Con más precisión, el tiempo de ejecución es O(n + I), donde I es el número de inversiones (pares desordenados). Si cada elemento está como máximo a k posiciones de su lugar final, I es como mucho n · k, así que insertion sort es O(n · k): muy rápido cuando k es pequeño.

Cómo se compara insertion sort con otros ordenamientos

AlgoritmoMejorPromedioPeorEspacio extraEstable
Insertion sortO(n)O(n²)O(n²)O(1)Sí
Bubble sortO(n)O(n²)O(n²)O(1)Sí
Selection sortO(n²)O(n²)O(n²)O(1)No
Merge sortO(n log n)O(n log n)O(n log n)O(n)Sí
QuicksortO(n log n)O(n log n)O(n²)O(log n)No
HeapsortO(n log n)O(n log n)O(n log n)O(1)No
Timsort (sorted de Python)O(n)O(n log n)O(n log n)O(n)Sí

Insertion sort es estable porque un elemento solo se mueve a la izquierda por encima de elementos estrictamente mayores. También es online: puede ordenar los datos a medida que llegan, manteniendo un prefijo ordenado en todo momento. Con listas cortas, su baja sobrecarga supera a los algoritmos O(n log n), así que Timsort (usado por Python y por Java para objetos) ordena las secuencias cortas con insertion sort binario, y muchas implementaciones de quicksort cambian a insertion sort por debajo de un tamaño pequeño.

Variantes y errores comunes

  • Insertion sort binario: búsqueda binaria de la posición y luego desplazamiento. Menos comparaciones, lo que ayuda cuando comparar es costoso.
  • Shell sort: aplica insertion sort a elementos separados por un hueco y luego reduce el hueco hasta 1. Mueve rápidamente los elementos lejanos y es mucho más rápido que insertion sort simple en arreglos grandes.
  • Insertion sort en listas enlazadas: no hace falta desplazar, pero encontrar la posición sigue siendo un recorrido lineal.

Cuándo usar insertion sort

Úsalo para arreglos pequeños (decenas de elementos), para datos casi ordenados, como una lista que se ordenó y a la que luego se añadieron unos pocos elementos, y cuando necesites un ordenamiento estable, simple e in situ. Para datos aleatorios grandes, usa un ordenamiento O(n log n); en Python eso significa sorted() o list.sort(), que ya aplican insertion sort internamente a las secuencias cortas.

Las preguntas de entrevista suelen pedir la traza, el mejor y el peor caso, por qué es estable o por qué supera a los algoritmos O(n log n) con entradas pequeñas y casi ordenadas.

Preguntas frecuentes

¿Es estable insertion sort?

Sí. Los elementos solo se mueven a la izquierda por encima de elementos estrictamente mayores, así que los elementos iguales mantienen su orden original.

¿Cuál es el mejor caso de insertion sort?

O(n), cuando la entrada ya está ordenada: cada elemento nuevo se compara una vez con su vecino de la izquierda y se queda en su sitio.

¿Por qué se usa insertion sort en Timsort?

Con secuencias cortas, su sobrecarga muy baja lo hace más rápido que merge sort o quicksort, y además es estable. Timsort usa insertion sort binario para ampliar las secuencias cortas antes de combinarlas.

¿Es insertion sort mejor que bubble sort?

Sí, en la práctica. Ambos son O(n²) y estables, pero insertion sort hace menos comparaciones y escrituras y se adapta mejor a entradas casi ordenadas.

¿La búsqueda binaria hace que insertion sort sea O(n log n)?

No. Reduce el número de comparaciones a O(n log n), pero desplazar elementos para hacer sitio sigue siendo O(n²) en el peor caso.

Todos los tutoriales de programación