Ordenación por burbuja
Recorre el array comparando cada pareja de vecinos y los intercambia si están al revés: en cada pasada el mayor que queda «sube» al final como una burbuja. Sencillo, estable y O(n²).
Visualízalo paso a paso
Cambia los datos, dale a reproducir y sigue cada paso en el dibujo, en la línea de Java que se ejecuta y en sus variables.
Ordenación por burbuja
Escribe los números y mira cómo cada pasada lleva el mayor que queda hasta el final.
- en la zona de trabajo
Paso 1
Array inicial: [5, 1, 4, 2, 8, 3].
1static void burbuja(int[] a) {
2 for (int i = 0; i < a.length - 1; i++) { // comparaciones = 0, intercambios = 0
3 boolean cambio = false;
4 for (int j = 0; j < a.length - 1 - i; j++) {
5 if (a[j] > a[j + 1]) {
6 int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
7 cambio = true;
8 }
9 }
10 if (!cambio) break;
11 }
12}Variables
- comparaciones
- 0
- intercambios
- 0
Atajos con el foco dentro del visualizador: ← → paso a paso, Espacio reproducir o pausar, Inicio/Fin ir al principio o al final.
La idea
La ordenación por burbuja es el primer método de ordenación que se aprende porque solo usa una idea: si dos elementos vecinos están al revés, se intercambian. Una pasada recorre el array de izquierda a derecha haciendo eso con cada pareja.
Al acabar la primera pasada, el mayor de todos ha ido «arrastrándose» de intercambio en intercambio hasta la última posición, como una burbuja que sube. En la segunda pasada sube el segundo mayor a la penúltima, y así sucesivamente: tras i pasadas, los i últimos ya están en su sitio y no hace falta volver a mirarlos.
Con n elementos bastan n − 1 pasadas. Y hay un atajo importante: si una pasada entera no hace ningún intercambio, todos los vecinos están en orden, así que el array ya está ordenado y se puede parar. Gracias a eso, un array que ya venía ordenado se comprueba con una sola pasada.
Es estable: dos elementos iguales nunca se intercambian (se compara con >, no con >=), así que conservan su orden original. Eso importa cuando se ordenan objetos por un campo y se quiere respetar un orden anterior.
Cuándo usarlo
- Para aprender: es el algoritmo más fácil de escribir y de razonar, y sirve para entender qué es una pasada, un intercambio o la estabilidad.
- Con muy pocos datos (una decena) o cuando el array casi siempre llega ya ordenado: con el corte anticipado, comprobarlo cuesta una sola pasada.
- Cuando solo se puede intercambiar vecinos (por ejemplo, elementos físicos en fila o redes de ordenación en hardware).
Cuándo no
- Con muchos datos: es O(n²) y hace muchísimos más intercambios que inserción o selección. Para eso están
Arrays.sort, mergesort o quicksort. - Si importan los movimientos (escribir es caro): selección hace como mucho n − 1 intercambios; burbuja puede hacer n²/2.
Paso a paso
- Comparar vecinos. Se recorre el array desde la posición 0 comparando
a[j]cona[j + 1]. - Intercambiar si están al revés. Si
a[j] > a[j + 1], se intercambian con una variable auxiliar. Si son iguales no se tocan, y así es estable. - El mayor llega al final. Al terminar la pasada, el mayor de la parte sin ordenar está en su última posición. La siguiente pasada puede pararse una posición antes.
- Repetir o parar. Se hacen como mucho n − 1 pasadas, pero si una pasada no ha intercambiado nada, el array ya está ordenado y se termina.
El código
Burbuja con corte anticipado
Cuenta las comparaciones y los intercambios para ver la diferencia entre un array desordenado, uno ya ordenado (una sola pasada) y uno al revés (el peor caso).
1import java.util.Arrays;
2
3public class Main {
4 static int comparaciones, intercambios;
5
6 /** Ordena a con el método de la burbuja; para en cuanto una pasada no intercambia nada. */
7 static void burbuja(int[] a) {
8 for (int i = 0; i < a.length - 1; i++) {
9 boolean cambio = false;
10 for (int j = 0; j < a.length - 1 - i; j++) { // los últimos i ya están en su sitio
11 comparaciones++;
12 if (a[j] > a[j + 1]) { // vecinos al revés: se intercambian
13 int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
14 intercambios++;
15 cambio = true;
16 }
17 }
18 if (!cambio) break; // ninguna pareja al revés: ya está ordenado
19 }
20 }
21
22 static void probar(int[] a) {
23 comparaciones = intercambios = 0;
24 String antes = Arrays.toString(a);
25 burbuja(a);
26 System.out.println(antes + " → " + Arrays.toString(a) + " (" + comparaciones + " comparaciones, " + intercambios + " intercambios)");
27 }
28
29 public static void main(String[] args) {
30 probar(new int[] {5, 1, 4, 2, 8, 3});
31 probar(new int[] {1, 2, 3, 4, 5, 6}); // ya ordenado: una sola pasada
32 probar(new int[] {6, 5, 4, 3, 2, 1}); // al revés: el peor caso
33 }
34}comparaciones = intercambios = 0
def burbuja(a):
"""Ordena a con el método de la burbuja; para en cuanto una pasada no intercambia nada."""
global comparaciones, intercambios
for i in range(len(a) - 1):
cambio = False
for j in range(len(a) - 1 - i): # los últimos i ya están en su sitio
comparaciones += 1
if a[j] > a[j + 1]: # vecinos al revés: se intercambian
a[j], a[j + 1] = a[j + 1], a[j]
intercambios += 1
cambio = True
if not cambio: # ninguna pareja al revés: ya está ordenado
break
def probar(a):
global comparaciones, intercambios
comparaciones = intercambios = 0
antes = str(a)
burbuja(a)
print(f"{antes} → {a} ({comparaciones} comparaciones, {intercambios} intercambios)")
probar([5, 1, 4, 2, 8, 3])
probar([1, 2, 3, 4, 5, 6]) # ya ordenado: una sola pasada
probar([6, 5, 4, 3, 2, 1]) # al revés: el peor casolet comparaciones = 0, intercambios = 0;
/** Ordena a con el método de la burbuja; para en cuanto una pasada no intercambia nada. */
function burbuja(a) {
for (let i = 0; i < a.length - 1; i++) {
let cambio = false;
for (let j = 0; j < a.length - 1 - i; j++) { // los últimos i ya están en su sitio
comparaciones++;
if (a[j] > a[j + 1]) { // vecinos al revés: se intercambian
[a[j], a[j + 1]] = [a[j + 1], a[j]];
intercambios++;
cambio = true;
}
}
if (!cambio) break; // ninguna pareja al revés: ya está ordenado
}
}
const texto = (a) => "[" + a.join(", ") + "]";
function probar(a) {
comparaciones = intercambios = 0;
const antes = texto(a);
burbuja(a);
console.log(`${antes} → ${texto(a)} (${comparaciones} comparaciones, ${intercambios} intercambios)`);
}
probar([5, 1, 4, 2, 8, 3]);
probar([1, 2, 3, 4, 5, 6]); // ya ordenado: una sola pasada
probar([6, 5, 4, 3, 2, 1]); // al revés: el peor casousing System;
class Program {
static int comparaciones, intercambios;
// Ordena a con el método de la burbuja; para en cuanto una pasada no intercambia nada.
static void Burbuja(int[] a) {
for (int i = 0; i < a.Length - 1; i++) {
bool cambio = false;
for (int j = 0; j < a.Length - 1 - i; j++) { // los últimos i ya están en su sitio
comparaciones++;
if (a[j] > a[j + 1]) { // vecinos al revés: se intercambian
(a[j], a[j + 1]) = (a[j + 1], a[j]);
intercambios++;
cambio = true;
}
}
if (!cambio) break; // ninguna pareja al revés: ya está ordenado
}
}
static string Texto(int[] a) => "[" + string.Join(", ", a) + "]";
static void Probar(int[] a) {
comparaciones = intercambios = 0;
string antes = Texto(a);
Burbuja(a);
Console.WriteLine(quot;{antes} → {Texto(a)} ({comparaciones} comparaciones, {intercambios} intercambios)");
}
static void Main() {
Probar(new[] { 5, 1, 4, 2, 8, 3 });
Probar(new[] { 1, 2, 3, 4, 5, 6 }); // ya ordenado: una sola pasada
Probar(new[] { 6, 5, 4, 3, 2, 1 }); // al revés: el peor caso
}
}<?php
$comparaciones = 0;
$intercambios = 0;
/** Ordena $a con el método de la burbuja; para en cuanto una pasada no intercambia nada. */
function burbuja(array &$a): void {
global $comparaciones, $intercambios;
$n = count($a);
for ($i = 0; $i < $n - 1; $i++) {
$cambio = false;
for ($j = 0; $j < $n - 1 - $i; $j++) { // los últimos $i ya están en su sitio
$comparaciones++;
if ($a[$j] > $a[$j + 1]) { // vecinos al revés: se intercambian
[$a[$j], $a[$j + 1]] = [$a[$j + 1], $a[$j]];
$intercambios++;
$cambio = true;
}
}
if (!$cambio) break; // ninguna pareja al revés: ya está ordenado
}
}
function texto(array $a): string { return "[" . implode(", ", $a) . "]"; }
function probar(array $a): void {
global $comparaciones, $intercambios;
$comparaciones = $intercambios = 0;
$antes = texto($a);
burbuja($a);
echo "$antes → " . texto($a) . " ($comparaciones comparaciones, $intercambios intercambios)\n";
}
probar([5, 1, 4, 2, 8, 3]);
probar([1, 2, 3, 4, 5, 6]); // ya ordenado: una sola pasada
probar([6, 5, 4, 3, 2, 1]); // al revés: el peor casoSalida al ejecutarlo (la misma en los 5 lenguajes)
[5, 1, 4, 2, 8, 3] → [1, 2, 3, 4, 5, 8] (14 comparaciones, 7 intercambios) [1, 2, 3, 4, 5, 6] → [1, 2, 3, 4, 5, 6] (5 comparaciones, 0 intercambios) [6, 5, 4, 3, 2, 1] → [1, 2, 3, 4, 5, 6] (15 comparaciones, 15 intercambios)
Ordenar textos
El algoritmo es el mismo; solo cambia cómo se decide que dos elementos están al revés.
1/** Con textos u objetos no vale >: se compara con compareTo (o con un Comparator). */
2static void burbuja(String[] a) {
3 for (int i = 0; i < a.length - 1; i++)
4 for (int j = 0; j < a.length - 1 - i; j++)
5 if (a[j].compareTo(a[j + 1]) > 0) { // a[j] va después que a[j + 1]
6 String t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
7 }
8}def burbuja(a):
"""En Python los textos se comparan con > igual que los números (por orden de sus caracteres)."""
for i in range(len(a) - 1):
for j in range(len(a) - 1 - i):
if a[j] > a[j + 1]: # a[j] va después que a[j + 1]
a[j], a[j + 1] = a[j + 1], a[j]/** Con textos se usa localeCompare, que además respeta las reglas del idioma (á, ñ…). */
function burbuja(a) {
for (let i = 0; i < a.length - 1; i++)
for (let j = 0; j < a.length - 1 - i; j++)
if (a[j].localeCompare(a[j + 1], "es") > 0) // a[j] va después que a[j + 1]
[a[j], a[j + 1]] = [a[j + 1], a[j]];
}// Con textos u objetos se compara con CompareTo (o con un IComparer).
static void Burbuja(string[] a) {
for (int i = 0; i < a.Length - 1; i++)
for (int j = 0; j < a.Length - 1 - i; j++)
if (string.CompareOrdinal(a[j], a[j + 1]) > 0) // a[j] va después que a[j + 1]
(a[j], a[j + 1]) = (a[j + 1], a[j]);
}/** Con textos se compara con strcmp (o con el operador <=>). */
function burbuja(array &$a): void {
$n = count($a);
for ($i = 0; $i < $n - 1; $i++)
for ($j = 0; $j < $n - 1 - $i; $j++)
if (strcmp($a[$j], $a[$j + 1]) > 0) // $a[$j] va después que $a[$j + 1]
[$a[$j], $a[$j + 1]] = [$a[$j + 1], $a[$j]];
}Traza: burbuja de {5, 1, 4, 2, 8, 3}
| Pasada | Array al terminar | Comparaciones | Intercambios |
|---|---|---|---|
| 1 | 1 4 2 5 3 8 | 5 | 4 |
| 2 | 1 2 4 3 5 8 | 4 | 2 |
| 3 | 1 2 3 4 5 8 | 3 | 1 |
| 4 | 1 2 3 4 5 8 | 2 | 0 → para |
En la primera pasada el 8 sube hasta el final; en la cuarta ya no hay intercambios y se para sin hacer la quinta.
Complejidad
| Caso | Comparaciones | Intercambios | Coste |
|---|---|---|---|
| Mejor (ya ordenado) | n − 1 | 0 | O(n) |
| Medio | ≈ n²/2 | ≈ n²/4 | O(n²) |
| Peor (al revés) | n(n − 1)/2 | n(n − 1)/2 | O(n²) |
Memoria extra: O(1), solo la variable del intercambio. Con 10.000 elementos al revés son unos 50 millones de comparaciones y otros tantos intercambios.
- Mejor caso: O(n)
- Caso medio: O(n²)
- Peor caso: O(n²)
El mejor caso (ya ordenado) es n solo si se corta cuando una pasada no intercambia nada. Las curvas grises son las demás clases, para comparar.
En la práctica
- Ninguna biblioteca la usa para ordenar:
Arrays.sortusa quicksort de doble pivote para tipos primitivos y TimSort (mezcla e inserción) para objetos. - La idea de «una pasada sin intercambios significa ordenado» es la forma más barata de comprobar si un array está ordenado: O(n).
- Su variante paralela (odd-even transposition sort) se usa en hardware y en redes de ordenación, donde cada procesador solo puede hablar con su vecino.
- Es la referencia con la que se compara cualquier otro algoritmo en clase: si tu método hace más intercambios que la burbuja, algo va mal.
Errores típicos
- Llegar con
jhastaa.length - 1en el bucle interno:a[j + 1]se sale del array (ArrayIndexOutOfBoundsException). El límite esj < a.length - 1 - i. - Intercambiar sin variable auxiliar (
a[j] = a[j + 1]; a[j + 1] = a[j];): los dos acaban con el mismo valor. - Comparar con
>=: intercambia elementos iguales, deja de ser estable y hace intercambios inútiles. - Declarar la bandera
cambiofuera del bucle de pasadas: tras la primera pasada con cambios nunca vuelve afalsey el corte anticipado no funciona. - No reducir el bucle interno con
- i: el resultado es correcto, pero compara cada vez con elementos que ya están en su sitio.
Ejercicios
Cada ejercicio se corrige solo con sus pruebas (algunas ocultas). Escribe tu solución en el editor y pulsa Ejecutar o Comprobar; la solución explicada está debajo, por si te atascas.
1. Burbuja pasada a pasada
Lee una línea de números enteros y ordénalos con el método de la burbuja mostrando el array al terminar cada pasada, con cuántos intercambios ha hecho. Si una pasada no intercambia nada, el array ya está ordenado: se para ahí. El main ya lee, valida y escribe: completa pasada, que hace una pasada sobre a[0..fin] y devuelve sus intercambios.
- Entrada: una línea con los números separados por espacios, por ejemplo
5 1 4 2 8 3. - Por cada pasada:
Pasada 1: 1 4 2 5 3 8 (intercambios: 4); al final,Ordenado: … con C comparaciones y S intercambios. - Errores:
No hay númerossi la línea está vacía yNúmero no válido: «x»si algo no es un entero.
Ejemplo
5 1 4 2 8 3
Pasada 1: 1 4 2 5 3 8 (intercambios: 4) Pasada 2: 1 2 4 3 5 8 (intercambios: 2) Pasada 3: 1 2 3 4 5 8 (intercambios: 1) Pasada 4: 1 2 3 4 5 8 (intercambios: 0) Ordenado: 1 2 3 4 5 8 con 14 comparaciones y 7 intercambios
Ver la solución explicada
1import java.util.*;
2
3public class Main {
4 static int comparaciones = 0, intercambios = 0;
5
6 /** Una pasada sobre a[0..fin]: compara cada pareja de vecinos, intercambia las que están al revés
7 y devuelve cuántos intercambios ha hecho. Suma a los contadores globales. */
8 static int pasada(int[] a, int fin) {
9 int cambios = 0;
10 for (int j = 0; j < fin; j++) {
11 comparaciones++;
12 if (a[j] > a[j + 1]) {
13 int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
14 cambios++;
15 }
16 }
17 intercambios += cambios;
18 return cambios;
19 }
20
21 static String texto(int[] a) {
22 StringJoiner sj = new StringJoiner(" ");
23 for (int x : a) sj.add(String.valueOf(x));
24 return sj.toString();
25 }
26
27 public static void main(String[] args) {
28 Scanner sc = new Scanner(System.in);
29 String linea = sc.hasNextLine() ? sc.nextLine().trim() : "";
30 if (linea.isEmpty()) {
31 System.out.println("No hay números");
32 return;
33 }
34 String[] partes = linea.split("\\s+");
35 int[] a = new int[partes.length];
36 for (int i = 0; i < partes.length; i++) {
37 try {
38 a[i] = Integer.parseInt(partes[i]);
39 } catch (NumberFormatException e) {
40 System.out.println("Número no válido: «" + partes[i] + "»");
41 return;
42 }
43 }
44 for (int i = 0; i < a.length - 1; i++) {
45 int cambios = pasada(a, a.length - 1 - i);
46 System.out.println("Pasada " + (i + 1) + ": " + texto(a) + " (intercambios: " + cambios + ")");
47 if (cambios == 0) break;
48 }
49 System.out.println("Ordenado: " + texto(a) + " con " + comparaciones + " comparaciones y " + intercambios + " intercambios");
50 }
51}Cada pasada lleva el mayor de a[0..fin] a la posición fin, por eso la siguiente se hace con un fin una unidad menor.
El número de intercambios de una pasada es justo el número de parejas que estaban al revés en ese recorrido; cuando es 0, todas las parejas de vecinos están en orden y eso implica que todo el array lo está.
2. Clasificación con empates
Cada línea es un participante de un concurso: su nombre (una palabra) y sus puntos. Ordénalos de más a menos puntos con el método de la burbuja, de forma que los empatados mantengan el orden en que llegaron, y escribe la clasificación con su puesto: los empatados comparten puesto y el siguiente salta (1, 1, 3). Completa ordenar y puestos.
- Entrada: líneas
nombre puntos, por ejemploAna 12. Los puntos son enteros de 0 a 999999. - Salida:
1. Luis 20 puntos(o1 punto), en orden. - Una línea mal escrita:
Línea no válida: «texto»(y se sigue con las demás). Si no queda nadie:No hay participantes.
Ejemplo
Ana 12 Luis 20 Eva 15 Marta 20 Pablo 12
1. Luis 20 puntos 1. Marta 20 puntos 3. Eva 15 puntos 4. Ana 12 puntos 4. Pablo 12 puntos
Ver la solución explicada
1import java.util.*;
2
3public class Main {
4 record Participante(String nombre, int puntos) { }
5
6 /** Burbuja por puntos, de más a menos. Solo se intercambia si el de la izquierda tiene MENOS
7 puntos: con empate no se mueven, así se conserva el orden de llegada (es estable). */
8 static void ordenar(List<Participante> l) {
9 for (int i = 0; i < l.size() - 1; i++) {
10 boolean cambio = false;
11 for (int j = 0; j < l.size() - 1 - i; j++) {
12 if (l.get(j).puntos() < l.get(j + 1).puntos()) {
13 Participante t = l.get(j);
14 l.set(j, l.get(j + 1));
15 l.set(j + 1, t);
16 cambio = true;
17 }
18 }
19 if (!cambio) break;
20 }
21 }
22
23 /** Puesto de cada participante (la lista ya está ordenada): los empatados comparten puesto
24 y el siguiente salta tantos como empatados haya (1, 1, 3). */
25 static int[] puestos(List<Participante> l) {
26 int[] p = new int[l.size()];
27 for (int i = 0; i < l.size(); i++)
28 p[i] = i > 0 && l.get(i).puntos() == l.get(i - 1).puntos() ? p[i - 1] : i + 1;
29 return p;
30 }
31
32 public static void main(String[] args) {
33 Scanner sc = new Scanner(System.in);
34 List<Participante> l = new ArrayList<>();
35 while (sc.hasNextLine()) {
36 String linea = sc.nextLine().trim();
37 if (linea.isEmpty()) continue;
38 String[] p = linea.split("\\s+");
39 if (p.length != 2 || !p[1].matches("\\d{1,6}")) {
40 System.out.println("Línea no válida: «" + linea + "»");
41 continue;
42 }
43 l.add(new Participante(p[0], Integer.parseInt(p[1])));
44 }
45 if (l.isEmpty()) {
46 System.out.println("No hay participantes");
47 return;
48 }
49 ordenar(l);
50 int[] puesto = puestos(l);
51 for (int i = 0; i < l.size(); i++) {
52 Participante x = l.get(i);
53 System.out.println(puesto[i] + ". " + x.nombre() + " " + x.puntos() + (x.puntos() == 1 ? " punto" : " puntos"));
54 }
55 }
56}La estabilidad sale gratis de comparar con < estricto: dos empatados nunca se intercambian, así que el que llegó antes sigue delante.
El puesto «de competición» (1, 1, 3) se calcula en una sola pasada sobre la lista ya ordenada, copiando el puesto del anterior cuando hay empate.
Test
Test: Ordenación por burbuja
0/5 respondidas · 0 aciertosElige una respuesta en cada pregunta: verás al momento si es correcta y por qué. Con un 80 % de aciertos se da por superada.
1.Tras la primera pasada de la burbuja sobre un array, ¿qué se puede asegurar?
2.¿Cuántas comparaciones hace la burbuja con corte anticipado sobre un array de 1.000 elementos ya ordenado?
3.¿Por qué la burbuja es estable?
4.¿Qué pasa si el bucle interno llega hasta
j < a.length?5.¿Cuál es el coste de la burbuja en el caso medio?