Imagine que você está em uma fila desorganizada esperando por um café. Para resolver a bagunça, o responsável pelo atendimento estabelece uma nova regra: “A fila precisa ser reorganizada por ordem de altura!”

Como você organizaria todo mundo?

O Bubble Sort (ou Ordenação por Flutuação) tem uma ideia muito simples e orgânica. Você vai do início ao fim da fila comparando as pessoas duas a duas. Se a pessoa da frente for maior que a pessoa de trás, elas trocam de lugar.

Fila de bonequinhos trocando de lugar

Ao fazer isso repetidas vezes, os maiores valores vão “borbulhando” para o final da fila, assim como bolhas de ar sobem até a superfície da água.


🔍 Entendendo o Passo a Passo

Vamos pegar um pequeno grupo de números totalmente caóticos:

5
0
3
1
8
2
4
3
2
4

Nosso objetivo é deixá-los em ordem crescente (do menor para o maior). Vamos iniciar o que chamamos de Passada 1 (ou Pass 1).

Passada 1

Começamos olhando para os dois primeiros elementos. Comparamos o 5 e o 3.

5
0
3
1
8
2
4
3
2
4

A regra é: se o número da esquerda for maior, eles trocam de lugar. 5 é maior que 3? Sim! Então trocamos.

3
0
5
1
8
2
4
3
2
4

Agora, avançamos uma casa. Vamos comparar o 5 (que andou para a direita) com o 8.

3
0
5
1
8
2
4
3
2
4

O 5 é maior que o 8? Não. Então eles ficam exatamente onde estão. Avançamos novamente. Comparamos o 8 e o 4.

3
0
5
1
8
2
4
3
2
4

O 8 é maior que 4? Sim! Então eles trocam de lugar.

3
0
5
1
4
2
8
3
2
4

Por fim, comparamos o 8 (que continua andando) e o 2.

3
0
5
1
4
2
8
3
2
4

8 é maior que 2? Com certeza. Eles trocam.

3
0
5
1
4
2
2
3
8
4

🎉 Fim da Passada 1! Percebeu o que aconteceu? O maior número de todos (o 8) flutuou como uma bolha gigante até o final do array. Agora sabemos com absoluta certeza que o último elemento está na posição correta.

Passada 2

Precisamos repetir o processo, mas agora não precisamos mais checar a última posição, porque o 8 já está ordenado.

Voltamos para o início: Comparamos 3 e 5.

3
0
5
1
4
2
2
3
8
4
Não trocam.

Comparamos 5 e 4.

3
0
5
1
4
2
2
3
8
4
O 5 é maior, então trocam.
3
0
4
1
5
2
2
3
8
4

Comparamos 5 e 2.

3
0
4
1
5
2
2
3
8
4
O 5 é maior, então trocam.
3
0
4
1
2
2
5
3
8
4

🎉 Fim da Passada 2! Agora o 5 está no seu lugar definitivo.

3
0
4
1
2
2
5
3
8
4

Passada 3

Começamos de novo com o que sobrou. Comparamos 3 e 4. Não trocam. Comparamos 4 e 2. O 4 é maior, então trocam.

3
0
2
1
4
2
5
3
8
4

🎉 Fim da Passada 3! O 4 encontrou seu lugar.

Passada 4 (Final)

Comparamos 3 e 2. O 3 é maior, então trocam.

2
0
3
1
4
2
5
3
8
4

O array está completamente ordenado! A paz voltou ao caos.

2
0
3
1
4
2
5
3
8
4


📜 Como fica no Código?

A implementação do Bubble Sort exige dois laços de repetição aninhados. Vamos analisar o porquê de cada linha existir e, em especial, entender a matemática por trás dos limites desses laços.

def bubble_sort(lista):
    n = len(lista)
    for i in range(n):
        for j in range(0, n - i - 1):
            if lista[j] > lista[j + 1]:
                lista[j], lista[j + 1] = lista[j + 1], lista[j]
                
    return lista

🧠 Dissecando a Lógica

Se a transição do visual para o código ainda não clicou perfeitamente, não se preocupe. Vamos olhar de perto como essas peças se encaixam:

  1. O controle de passadas (for i in range(n)): Pense nesse laço como o maestro da operação. Ele não mexe nos elementos, apenas dita quantas vezes precisamos percorrer a fila. Como no pior dos casos temos n elementos fora do lugar, ele nos dá n rodadas para garantir que cada bolha chegue ao topo.

  2. Ignorando o que já está pronto (n - i - 1): Aqui está a grande sacada matemática do algoritmo!

    • A cada volta que o maestro (i) completa, sabemos que um novo número alcançou o seu destino final lá na ponta direita.
    • A subtração - i serve para dizer pro código: “Ei, poupe energia! Não precisa olhar o final da fila, a gente já arrumou essa parte nas passadas anteriores”.
    • E o - 1? Como o código sempre compara o elemento atual (j) com o vizinho seguinte (j + 1), nós precisamos parar um passo antes da fronteira. Se formos até o fim, o j + 1 vai tentar ler um espaço vazio, gerando um erro de programa.
  3. Trocando os elementos de lugar: Em muitas linguagens antigas, você precisaria criar uma variável auxiliar para guardar um valor antes de trocá-lo. O Python permite fazer arr[j], arr[j + 1] = arr[j + 1], arr[j]. É uma forma super elegante e direta de trocar duas variáveis de lugar na mesma linha.

⏳ Complexidade (Big O)

Vamos pensar juntos. Se tivermos 10 elementos, faremos cerca de 10 comparações na primeira passada, 9 na segunda, 8 na terceira… isso dá um número de operações que cresce em proporção quadrada ao número de elementos.

  • Pior Caso: Se o array estiver totalmente ao contrário, teremos que fazer todas as comparações e trocas possíveis. Isso leva a um tempo de O(n²).
  • Caso Médio: Também é O(n²).
  • Melhor Caso: Se a lista já estiver ordenada, podemos adicionar um truque no código para parar mais cedo. Mesmo assim, a versão clássica que escrevemos olhará os elementos e custará O(n²), embora uma versão otimizada leve O(n).

O Bubble Sort é lento para listas grandes. Lembra da pilha de 1.000 livros? Em um Bubble Sort no pior caso, faríamos 1000 * 1000 = 1 milhão de comparações! Haja café para esperar isso rodar.

Apesar de ser lento na vida real, ele é excelente para aprender a pensar em algoritmos. Nos próximos capítulos, vamos ver estratégias muito mais espertas que o Bubble Sort.