Programación · Algoritmos
Bubble sort (ordenamiento de burbuja): cómo funciona, código y complejidad
Respuesta corta
Bubble sort es un algoritmo de ordenamiento sencillo que recorre repetidamente una lista e intercambia cada par de elementos adyacentes que están en el orden equivocado. Tras cada pasada, el mayor elemento restante ha subido, o «burbujeado», hasta su posición final al final de la lista. Tarda O(n²) en el caso promedio y en el peor, y O(n) en una lista que ya está ordenada; usa O(1) de espacio extra y es estable. Se usa sobre todo para enseñar; los programas reales usan la función de ordenamiento integrada.
Abrir Ordenar líneasLa idea en palabras sencillas
Compara los dos primeros elementos. Si el primero es mayor, intercámbialos. Luego compara el segundo y el tercero, después el tercero y el cuarto, y así hasta el final de la lista. Esto es una pasada. Tras la primera pasada, el mayor elemento queda garantizado en la última posición, porque cada comparación lo desplazó un paso a la derecha.
Repite la pasada sobre la parte sin ordenar, que se reduce en un elemento cada vez. Si una pasada completa no hace ningún intercambio, la lista está ordenada y puedes detenerte antes.
Ejemplo resuelto, pasada a pasada
Ordena [5, 1, 4, 2, 8] de forma ascendente. Los elementos situados después de la barra ya están en su posición final.
| Pasada | Comparaciones e intercambios | Lista tras la pasada |
|---|---|---|
| 1 | 5↔1 intercambio, 5↔4 intercambio, 5↔2 intercambio, 5 y 8 se mantienen | [1, 4, 2, 5, 8] (8 colocado) |
| 2 | 1 y 4 se mantienen, 4↔2 intercambio, 4 y 5 se mantienen | [1, 2, 4, 5, 8] (5 colocado) |
| 3 | 1 y 2 se mantienen, 2 y 4 se mantienen, sin intercambios | [1, 2, 4, 5, 8] ordenada, se detiene |
Sin la salida anticipada, el algoritmo haría una cuarta pasada. Con ella, aquí bastan tres pasadas.
Implementación en Python
def bubble_sort(items):
"""Sort a list in place, ascending. Returns the same list."""
n = len(items)
for end in range(n - 1, 0, -1): # last index of the unsorted part
swapped = False
for i in range(end):
if items[i] > items[i + 1]: # strict >, keeps equal items in order
items[i], items[i + 1] = items[i + 1], items[i]
swapped = True
if not swapped: # no swaps: already sorted
break
return items
print(bubble_sort([5, 1, 4, 2, 8])) # [1, 2, 4, 5, 8]
print(bubble_sort([3, 3, 1])) # [1, 3, 3]
print(bubble_sort([])) # []El bucle interno se detiene en end porque todo lo que hay después ya está en su sitio. La bandera swapped da el mejor caso O(n) con una entrada ordenada.
Complejidad temporal y espacial
| Caso | Comparaciones | Tiempo | Motivo |
|---|---|---|---|
| Mejor (ya ordenada) | n − 1 | O(n) | una pasada sin intercambios y se detiene |
| Promedio (orden aleatorio) | unas n²/2 | O(n²) | unos n²/4 intercambios en promedio |
| Peor (orden inverso) | n(n − 1)/2 | O(n²) | cada comparación es un intercambio |
| Espacio extra | O(1) | ordena in situ con unas pocas variables |
Con 10.000 elementos en orden inverso, son casi 50 millones de comparaciones e intercambios. El número de intercambios siempre es igual al número de inversiones, que son los pares de elementos desordenados entre sí.
Cómo se compara bubble sort con otros ordenamientos
| Algoritmo | Mejor | Promedio | Peor | Espacio extra | Estable |
|---|---|---|---|---|---|
| Bubble sort | O(n) | O(n²) | O(n²) | O(1) | Sí |
| Selection sort | O(n²) | O(n²) | O(n²) | O(1) | No |
| Insertion sort | O(n) | O(n²) | O(n²) | O(1) | Sí |
| Merge sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Sí |
| Quicksort | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heapsort | O(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í |
Bubble sort es estable porque solo intercambia elementos adyacentes y solo cuando están estrictamente desordenados, así que los elementos iguales nunca se adelantan entre sí. Insertion sort tiene la misma complejidad y estabilidad, pero en la práctica hace menos escrituras y es más rápido, por lo que se usa él, y no bubble sort, dentro de algoritmos híbridos como Timsort.
Variantes y errores comunes
- Cocktail shaker sort recorre la lista de izquierda a derecha y luego de derecha a izquierda en pasadas alternas, lo que lleva más rápido al principio los elementos pequeños que están al final (llamados tortugas). Sigue siendo O(n²).
- Comb sort compara elementos separados por un hueco y va reduciendo ese hueco, lo que elimina muchas tortugas pronto; con hueco 1 se convierte en bubble sort.
- Odd-even transposition sort compara todos los pares impares y luego todos los pares pares, y se usa para enseñar ordenamiento en paralelo.
Cuándo usar bubble sort
Casi nunca en código de producción. En Python, llama a sorted(items) o items.sort(), que usan Timsort, se ejecutan en O(n log n) y son estables. Aun así, conviene conocer bubble sort porque es el ordenamiento más fácil de explicar, su demostración de corrección es sencilla de seguir y es una primera pregunta habitual de entrevistas y exámenes sobre bucles, intercambios y complejidad.
La única ventaja práctica es detectar una lista ordenada en una sola pasada O(n), pero un simple bucle que compare vecinos lo hace sin ordenar nada.
Preguntas frecuentes
¿Es estable bubble sort?
Sí. Solo intercambia elementos adyacentes cuando el de la izquierda es estrictamente mayor, así que los elementos iguales conservan su orden original.
¿Cuál es la complejidad temporal de bubble sort?
O(n²) en el caso promedio y en el peor. Con una salida anticipada cuando una pasada no hace intercambios, el mejor caso con una entrada ya ordenada es O(n).
¿Por qué se llama bubble sort?
Los elementos grandes se desplazan hacia el final de la lista un intercambio a la vez, como burbujas que suben a la superficie. Tras la pasada k, los k elementos mayores están en su sitio.
¿Es bubble sort más rápido que insertion sort?
No. Ambos son O(n²), pero insertion sort suele hacer menos operaciones y es más rápido en la práctica, sobre todo con datos casi ordenados.
¿Usa bubble sort memoria adicional?
No. Ordena in situ y solo necesita O(1) de espacio extra para los índices del bucle y un valor temporal durante un intercambio.