Apuntes DAM
Volver al inicio

Ordenación por burbuja

AlgoritmosOrdenaciónNivel básicoTambién: bubble sort, método de la burbuja, ordenación por intercambio

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.

De 2 a 16 enteros separados por espacios
  • 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

  1. Comparar vecinos. Se recorre el array desde la posición 0 comparando a[j] con a[j + 1].
  2. 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.
  3. 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.
  4. 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).

Java
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}

Salida 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.

Java
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}

Traza: burbuja de {5, 1, 4, 2, 8, 3}

PasadaArray al terminarComparacionesIntercambios
11 4 2 5 3 854
21 2 4 3 5 842
31 2 3 4 5 831
41 2 3 4 5 820 → 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

CasoComparacionesIntercambiosCoste
Mejor (ya ordenado)n − 10O(n)
Medio≈ n²/2≈ n²/4O(n²)
Peor (al revés)n(n − 1)/2n(n − 1)/2O(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.

0102030405015101520tamaño de la entrada (n)operacionesO(n!)O(2ⁿ)O(n²)O(n log n)O(1)O(log n)O(n)
  • 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.sort usa 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 j hasta a.length - 1 en el bucle interno: a[j + 1] se sale del array (ArrayIndexOutOfBoundsException). El límite es j < 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 cambio fuera del bucle de pasadas: tras la primera pasada con cambios nunca vuelve a false y 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úmeros si la línea está vacía y Número no válido: «x» si algo no es un entero.
☕JavaBurbuja pasada a pasadaFácil

Ejemplo

Entrada (lo que se escribe por teclado)
5 1 4 2 8 3
Salida esperada
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
⏳
Test oculto #3
⏳
Test oculto #4
⏳
Test oculto #5
⏳
Test oculto #6
0/6 tests pasados · pulsa un test para ver su entrada y su salida esperada
Ver la solución explicada
java
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 ejemplo Ana 12. Los puntos son enteros de 0 a 999999.
  • Salida: 1. Luis 20 puntos (o 1 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.
☕JavaClasificación con empatesMedio

Ejemplo

Entrada (lo que se escribe por teclado)
Ana 12
Luis 20
Eva 15
Marta 20
Pablo 12
Salida esperada
1. Luis 20 puntos
1. Marta 20 puntos
3. Eva 15 puntos
4. Ana 12 puntos
4. Pablo 12 puntos
⏳
Test oculto #3
⏳
Test oculto #4
⏳
Test oculto #5
0/5 tests pasados · pulsa un test para ver su entrada y su salida esperada
Ver la solución explicada
java
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 aciertos

Elige 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. 1.Tras la primera pasada de la burbuja sobre un array, ¿qué se puede asegurar?

  2. 2.¿Cuántas comparaciones hace la burbuja con corte anticipado sobre un array de 1.000 elementos ya ordenado?

  3. 3.¿Por qué la burbuja es estable?

  4. 4.¿Qué pasa si el bucle interno llega hasta j < a.length?

  5. 5.¿Cuál es el coste de la burbuja en el caso medio?

Relacionado