Nesta aula, vamos explorar três algoritmos de ordenação clássicos: Bubble Sort, Insertion Sort e Selection Sort. Eles são os primeiros passos para entender como podemos organizar dados de forma eficiente. A ordenação é uma operação fundamental em computação, utilizada em diversas aplicações, desde organização de listas até indexação de bancos de dados.

Bubble Sort

O Bubble Sort, ou ordenação por bolha, é um dos algoritmos mais simples de entender. Ele funciona percorrendo repetidamente a lista, comparando elementos adjacentes e trocando-os se estiverem na ordem errada. Esse processo se repete até que nenhuma troca seja necessária, indicando que a lista está ordenada.

Vamos considerar um exemplo com o array [5, 3, 8, 1]:

  1. Primeira passagem: compara 5 e 3 → troca (3, 5, 8, 1); compara 5 e 8 → mantém; compara 8 e 1 → troca (3, 5, 1, 8).
  2. Segunda passagem: (3, 5, 1, 8) → compara 3 e 5 mantém; 5 e 1 troca (3, 1, 5, 8); 5 e 8 mantém.
  3. Terceira passagem: (3, 1, 5, 8) → 3 e 1 troca (1, 3, 5, 8); 3 e 5 mantém; fim.

Ao final, temos o array ordenado.

Implementação em Python:

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

Análise de Complexidade

O Bubble Sort tem complexidade O(n²) no pior caso (quando a lista está invertida) e O(n) no melhor caso (quando já está ordenada, se implementarmos uma otimização). No entanto, em média, é O(n²), tornando-o ineficiente para grandes conjuntos de dados.

Insertion Sort

O Insertion Sort constrói a lista ordenada gradualmente. Para cada elemento, ele encontra a posição correta inserindo-o na parte já ordenada, deslocando os elementos maiores para a direita. É o algoritmo que muitas pessoas usam intuitivamente ao ordenar cartas de baralho.

Exemplo com [5, 3, 8, 1]:

  1. Começa com 5 (já ordenado).
  2. Pega 3, compara com 5, desloca 5 para a direita e insere 3 na posição 0: [3, 5, 8, 1].
  3. Pega 8, já está maior que 5, mantém: [3, 5, 8, 1].
  4. Pega 1, desloca 8,5,3 para a direita e insere 1 no início: [1, 3, 5, 8].

Implementação em Python:

def insertion_sort(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1
        while j >= 0 and key < arr[j]:
            arr[j+1] = arr[j]
            j -= 1
        arr[j+1] = key
    return arr

Análise de Complexidade

O Insertion Sort também é O(n²) no pior caso, mas seu melhor caso é O(n) quando a lista já está ordenada. Ele é eficiente para listas pequenas ou parcialmente ordenadas, sendo até mesmo utilizado como componente de algoritmos híbridos como o Timsort.

Selection Sort

O Selection Sort funciona selecionando repetidamente o menor elemento da parte não ordenada e trocando-o com o primeiro elemento não ordenado. Ele é intuitivo, porém não é estável (a ordem relativa de elementos iguais pode ser alterada).

Exemplo com [5, 3, 8, 1]:

  1. Menor elemento é 1, troca com 5: [1, 3, 8, 5].
  2. Agora ordenado começa em índice 1: menor entre [3,8,5] é 3, mantém.
  3. Entre [8,5] menor é 5, troca com 8: [1,3,5,8].

Implementação em Python:

def selection_sort(arr):
    for i in range(len(arr)):
        min_idx = i
        for j in range(i+1, len(arr)):
            if arr[j] < arr[min_idx]:
                min_idx = j
        arr[i], arr[min_idx] = arr[min_idx], arr[i]
    return arr

Análise de Complexidade

O Selection Sort tem complexidade O(n²) independentemente da ordem inicial. Embora simples, seu desempenho é inferior ao Insertion Sort na prática para a maioria dos cenários. A principal vantagem é que ele faz no máximo O(n) trocas, o que pode ser útil quando escrever na memória é caro.

Comparação entre os Algoritmos

A tabela abaixo resume as principais características:

AlgoritmoMelhor CasoPior CasoEstável
Bubble SortO(n)O(n²)Sim
Insertion SortO(n)O(n²)Sim
Selection SortO(n²)O(n²)Não

Pontos-Chave

  • Bubble Sort, Insertion Sort e Selection Sort são algoritmos de ordenação O(n²) no pior caso.
  • Insertion Sort é o mais eficiente entre eles para listas pequenas ou quase ordenadas.
  • Selection Sort não é estável e faz sempre O(n²) comparações, mas o número de trocas é O(n).
  • Para grandes volumes de dados, devemos optar por algoritmos como Merge Sort, Quick Sort ou Heap Sort.

Perguntas Frequentes

1. Qual a diferença entre Bubble Sort e Insertion Sort?

O Bubble Sort realiza trocas sucessivas entre pares adjacentes até ordenar, enquanto o Insertion Sort insere cada elemento na posição correta deslocando os demais. O Insertion Sort costuma ser mais rápido em listas pequenas.

2. O Selection Sort é estável?

A implementação padrão do Selection Sort não é estável, pois a troca do menor elemento com o primeiro pode alterar a ordem relativa de elementos iguais.

3. Qual desses algoritmos devo usar no dia a dia?

Em linguagens de programação, funções de ordenação nativas já implementam algoritmos eficientes (como Timsort no Python). Mas entender esses três algoritmos é fundamental para aprender análises e técnicas mais avançadas.