DEV Community

Cover image for Entendendo Bubble Sort
Mr Punk da Silva
Mr Punk da Silva

Posted on • Edited on

Entendendo Bubble Sort

O que é Bubble Sort?

O Bubble Sort é um algoritmo de ordenação simples que funciona comparando elementos adjacentes e trocando-os se estiverem na ordem errada. O nome vem do fato de que os elementos menores "borbulham" para o início da lista, assim como bolhas de ar sobem para a superfície da água.

Como funciona?

O algoritmo funciona da seguinte forma:

  1. Compara elementos adjacentes no array
  2. Troca os elementos se estiverem na ordem errada (o maior vai para a direita)
  3. Repete o processo para todos os pares adjacentes
  4. Continua as iterações até que nenhuma troca seja necessária

Diagramação

Configura aqui

https://raw.githubusercontent.com/mrpunkdasilva/learn-sorting-algorithms/d4f220e951a76b8bf0b892b816e461e6053dbdde/Writerside/images/bubbleSort_annotated.png

Exemplo Visual

Considerando o array: [64, 34, 25, 12, 22, 11, 90]

Iteração 1:

  • Compara 64 e 34: 64 > 34 → Troca: [34, 64, 25, 12, 22, 11, 90]
  • Compara 64 e 25: 64 > 25 → Troca: [34, 25, 64, 12, 22, 11, 90]
  • Compara 64 e 12: 64 > 12 → Troca: [34, 25, 12, 64, 22, 11, 90]
  • Compara 64 e 22: 64 > 22 → Troca: [34, 25, 12, 22, 64, 11, 90]
  • Compara 64 e 11: 64 > 11 → Troca: [34, 25, 12, 22, 11, 64, 90]
  • Compara 64 e 90: 64 < 90 → Sem troca: [34, 25, 12, 22, 11, 64, 90]
  • Resultado: O maior elemento (90) está na posição correta

Iteração 2:

  • Compara 34 e 25: 34 > 25 → Troca: [25, 34, 12, 22, 11, 64, 90]
  • Compara 34 e 12: 34 > 12 → Troca: [25, 12, 34, 22, 11, 64, 90]
  • Compara 34 e 22: 34 > 22 → Troca: [25, 12, 22, 34, 11, 64, 90]
  • Compara 34 e 11: 34 > 11 → Troca: [25, 12, 22, 11, 34, 64, 90]
  • Compara 34 e 64: 34 < 64 → Sem troca
  • Resultado: Os dois maiores elementos estão nas posições corretas

Iteração 3:

  • Compara 25 e 12: 25 > 12 → Troca: [12, 25, 22, 11, 34, 64, 90]
  • Compara 25 e 22: 25 > 22 → Troca: [12, 22, 25, 11, 34, 64, 90]
  • Compara 25 e 11: 25 > 11 → Troca: [12, 22, 11, 25, 34, 64, 90]
  • Compara 25 e 34: 25 < 34 → Sem troca

O processo continua até que nenhuma troca seja necessária, resultando em: [11, 12, 22, 25, 34, 64, 90]


Implementação

Nossa implementação educativa inclui saídas detalhadas para ajudar no aprendizado.

Você pode encontrar uma implementação completa e educativa do Bubble Sort em:

- 📁 Domus/Domus-1/bubbleSort.cpp

Função Principal - Bubble Sort Algorithm

void bubbleSortAlgorithm(int dataArray[], int arraySize)
{
    cout << "========================================" << endl;
    cout << "STARTING BUBBLE SORT ALGORITHM" << endl;
    cout << "========================================" << endl;
    cout << "Initial array: ";
    for(int displayIndex = 0; displayIndex < arraySize; displayIndex++) {
        cout << dataArray[displayIndex] << " ";
    }
    cout << endl << endl;

    int totalNumberOfSwaps = 0;
    int totalNumberOfComparisons = 0;
    bool hasSwapped = true;
    int iterationCount = 0;

    while (hasSwapped && iterationCount < arraySize - 1)
    {
        iterationCount++;
        hasSwapped = false;

        cout << ">>> ITERATION " << iterationCount << " <<<" << endl;
        cout << "Comparing adjacent elements..." << endl;

        for (int currentIndex = 0; currentIndex < arraySize - iterationCount; currentIndex++)
        {
            int nextIndex = currentIndex + 1;
            totalNumberOfComparisons++;

            cout << "Comparing dataArray[" << currentIndex << "] = " << dataArray[currentIndex] 
                 << " with dataArray[" << nextIndex << "] = " << dataArray[nextIndex];

            if (dataArray[currentIndex] > dataArray[nextIndex]) {
                cout << " -> " << dataArray[currentIndex] << " > " << dataArray[nextIndex] 
                     << ", need to swap!" << endl;
                swapElements(dataArray, currentIndex, nextIndex);
                hasSwapped = true;
                totalNumberOfSwaps++;
            } else {
                cout << " -> " << dataArray[currentIndex] << " <= " << dataArray[nextIndex] 
                     << ", no swap needed" << endl;
            }
        }

        cout << "Array state after iteration " << iterationCount << ": ";
        for(int displayIndex = 0; displayIndex < arraySize; displayIndex++) {
            if (displayIndex >= arraySize - iterationCount) {
                cout << "[" << dataArray[displayIndex] << "] "; // Already sorted elements
            } else {
                cout << dataArray[displayIndex] << " ";        // Not yet sorted elements
            }
        }
        cout << endl;
        cout << "Elements in final position: " << iterationCount << "/" << arraySize << endl;

        if (!hasSwapped) {
            cout << "No swaps performed in this iteration - array is sorted!" << endl;
        }
        cout << "--------------------------------" << endl;
    }

    cout << "========================================" << endl;
    cout << "BUBBLE SORT ALGORITHM COMPLETED!" << endl;
    cout << "Total number of iterations: " << iterationCount << endl;
    cout << "Total number of comparisons: " << totalNumberOfComparisons << endl;
    cout << "Total number of swaps performed: " << totalNumberOfSwaps << endl;
    cout << "========================================" << endl;
}
Enter fullscreen mode Exit fullscreen mode

Função para Trocar Elementos

void swapElements(int dataArray[], int firstPosition, int secondPosition)
{
    cout << "  -> Swapping elements: " << dataArray[firstPosition] << " (position " << firstPosition << ") <-> " << dataArray[secondPosition] << " (position " << secondPosition << ")" << endl;
    int temporaryValue = dataArray[firstPosition];
    dataArray[firstPosition] = dataArray[secondPosition];
    dataArray[secondPosition] = temporaryValue;
    cout << "  -> After swap: position " << firstPosition << " = " << dataArray[firstPosition] << ", position " << secondPosition << " = " << dataArray[secondPosition] << endl;
}
Enter fullscreen mode Exit fullscreen mode

Versão Otimizada do Bubble Sort

void optimizedBubbleSortAlgorithm(int dataArray[], int arraySize)
{
    cout << "========================================" << endl;
    cout << "STARTING OPTIMIZED BUBBLE SORT ALGORITHM" << endl;
    cout << "========================================" << endl;

    int totalNumberOfSwaps = 0;
    int totalNumberOfComparisons = 0;

    for (int iteration = 0; iteration < arraySize - 1; iteration++)
    {
        bool hasSwapped = false;

        cout << ">>> ITERATION " << (iteration + 1) << " <<<" << endl;

        for (int currentIndex = 0; currentIndex < arraySize - iteration - 1; currentIndex++)
        {
            totalNumberOfComparisons++;

            if (dataArray[currentIndex] > dataArray[currentIndex + 1]) {
                swapElements(dataArray, currentIndex, currentIndex + 1);
                hasSwapped = true;
                totalNumberOfSwaps++;
            }
        }

        // Early termination if no swaps occurred
        if (!hasSwapped) {
            cout << "No swaps in this iteration - array is already sorted!" << endl;
            break;
        }

        cout << "Array after iteration " << (iteration + 1) << ": ";
        for(int displayIndex = 0; displayIndex < arraySize; displayIndex++) {
            cout << dataArray[displayIndex] << " ";
        }
        cout << endl << "--------------------------------" << endl;
    }

    cout << "Total comparisons: " << totalNumberOfComparisons << endl;
    cout << "Total swaps: " << totalNumberOfSwaps << endl;
}
Enter fullscreen mode Exit fullscreen mode

Características do Algoritmo

Complexidade de Tempo

  • Melhor caso: O(n) - Array já ordenado (com otimização)
  • Caso médio: O(n²) - Comportamento típico
  • Pior caso: O(n²) - Array ordenado inversamente

Complexidade de Espaço

  • O(1) - Algoritmo in-place, usa apenas memória constante adicional

Propriedades Importantes

Propriedade Valor
Estável ✅ Sim
In-place ✅ Sim
Adaptivo ✅ Sim (com otimização)
Comparações O(n²)
Trocas O(n²)

Por que o Bubble Sort É Estável?

O que significa "Estabilidade" em algoritmos de ordenação?

Um algoritmo de ordenação é estável quando mantém a ordem relativa dos elementos que possuem valores iguais. Ou seja, se dois elementos têm o mesmo valor, aquele que aparece primeiro no array original deve aparecer primeiro no array ordenado.

Exemplo Prático de Estabilidade

Considere um array de cartas onde cada carta tem um valor e um naipe:

Array inicial: [5♠, 3♦, 5♥, 2♣, 3♠]

Vamos ordenar por valor numérico apenas, ignorando o naipe:

✅ Bubble Sort (estável):

[2♣, 3♦, 3♠, 5♠, 5♥]

  • Note que 3♦ vem antes de 3♠ (mantém ordem original)
  • E 5♠ vem antes de 5♥ (mantém ordem original)

Por que o Bubble Sort mantém a estabilidade?

O Bubble Sort mantém a estabilidade porque:

  1. Compara apenas elementos adjacentes
  2. Só troca elementos se o da esquerda for MAIOR que o da direita
  3. Nunca troca elementos iguais

Demonstração com números simples:

Array: [4, 2a, 2b, 1] (onde 2a e 2b têm o mesmo valor, mas origens diferentes)

Iteração 1:

  • Compara 4 e 2a: 4 > 2a → Troca: [2a, 4, 2b, 1]
  • Compara 4 e 2b: 4 > 2b → Troca: [2a, 2b, 4, 1]
  • Compara 4 e 1: 4 > 1 → Troca: [2a, 2b, 1, 4]

Iteração 2:

  • Compara 2a e 2b: 2a == 2bSem troca (preserva ordem!)
  • Compara 2b e 1: 2b > 1 → Troca: [2a, 1, 2b, 4]

Iteração 3:

  • Compara 2a e 1: 2a > 1 → Troca: [1, 2a, 2b, 4]

Resultado final: [1, 2a, 2b, 4] ✅ Ordem original mantida!

Exemplo Prático com Dados Reais

struct Pessoa {
    string nome;
    int idade;
    int numeroChegada; // Para identificar ordem original
};

// Array inicial (ordenado por chegada):
// 1. João, 25 anos
// 2. Maria, 30 anos  
// 3. Pedro, 25 anos
// 4. Ana, 20 anos

// Após Bubble Sort por idade:
// 1. Ana, 20 anos
// 2. João, 25 anos     <- João mantém prioridade sobre Pedro
// 3. Pedro, 25 anos    <- Pedro vem depois (ordem original preservada)
// 4. Maria, 30 anos
Enter fullscreen mode Exit fullscreen mode

Importância da Estabilidade

A estabilidade é crucial quando:

  • Ordenação múltipla: Primeiro por um campo, depois por outro
  • Preservação de contexto: Manter informações sobre ordem original
  • Interfaces de usuário: Comportamento previsível para o usuário
  • Dados com metadados: Timestamps, IDs, etc.

Comparação com Algoritmos Instáveis

Algoritmo Estável? Motivo
Bubble Sort ✅ Sim Só troca adjacentes se forem diferentes
Selection Sort ❌ Não Troca elementos distantes
Insertion Sort ✅ Sim Insere mantendo ordem
Quick Sort ❌ Não Particionamento pode alterar ordem
Merge Sort ✅ Sim Merge preserva ordem quando iguais

Implementação que Garante Estabilidade

void stableBubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            // CRUCIAL: usar > e não >=
            if (arr[j] > arr[j + 1]) {  // Não troca elementos iguais!
                swap(arr[j], arr[j + 1]);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

🔑 Ponto-chave: Use > (maior que) e nunca >= (maior ou igual) na condição de troca para manter a estabilidade!


Vantagens vs. Disvantagens

Vantagens

  • Simples de implementar e entender
  • Estável: Mantém a ordem relativa de elementos iguais
  • In-place: Não requer memória adicional
  • Adaptivo: Com otimização pode detectar arrays já ordenados
  • Funciona bem com arrays pequenos
  • Detecta facilmente se o array já está ordenado

Desvantagens

  • Complexidade O(n²): Ineficiente para arrays grandes
  • Muitas trocas: Pode fazer até O(n²) trocas no pior caso
  • Lento na prática: Mesmo entre algoritmos O(n²)
  • Não recomendado para dados em produção
  • Elementos pequenos "borbulham" lentamente para o início

Quando Usar?

O Bubble Sort é adequado quando:

  • Arrays muito pequenos (< 10 elementos)
  • Estabilidade é crucial (manter ordem relativa de elementos iguais)
  • Detecção de ordenação é importante (pode parar cedo se já ordenado)
  • Fins educacionais (aprender conceitos de ordenação)
  • Simplicidade extrema é mais importante que eficiência
  • Protótipos rápidos onde performance não é crítica

Comparação com Outros Algoritmos

Algoritmo Melhor Caso Caso Médio Pior Caso Estável Trocas
Bubble Sort O(n) O(n²) O(n²) O(n²)
Selection Sort O(n²) O(n²) O(n²) O(n)
Insertion Sort O(n) O(n²) O(n²) O(n²)
Merge Sort O(n log n) O(n log n) O(n log n) -
Quick Sort O(n log n) O(n log n) O(n²) O(n log n)

Variações do Bubble Sort

1. Bubble Sort Otimizado (com Flag)

Adiciona uma flag para detectar quando o array já está ordenado e para antecipadamente.

void optimizedBubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        bool hasSwapped = false;

        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr[j], arr[j + 1]);
                hasSwapped = true;
            }
        }

        // Se não houve trocas, array está ordenado
        if (!hasSwapped) {
            break;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Cocktail Sort (Bubble Sort Bidirecional)

Funciona em ambas as direções alternadamente, melhorando a performance em alguns casos.

void cocktailSort(int arr[], int n) {
    bool hasSwapped = true;
    int start = 0;
    int end = n - 1;

    while (hasSwapped) {
        hasSwapped = false;

        // Esquerda para direita
        for (int i = start; i < end; i++) {
            if (arr[i] > arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                hasSwapped = true;
            }
        }
        end--;

        if (!hasSwapped) break;

        // Direita para esquerda
        for (int i = end; i > start; i--) {
            if (arr[i] < arr[i - 1]) {
                swap(arr[i], arr[i - 1]);
                hasSwapped = true;
            }
        }
        start++;
    }
}
Enter fullscreen mode Exit fullscreen mode

3. Bubble Sort Recursivo

Implementação recursiva que "borbulha" o maior elemento e ordena recursivamente o restante.

void recursiveBubbleSort(int arr[], int n) {
    // Caso base
    if (n == 1) return;

    // Uma passada para colocar o maior elemento no final
    for (int i = 0; i < n - 1; i++) {
        if (arr[i] > arr[i + 1]) {
            swap(arr[i], arr[i + 1]);
        }
    }

    // Chama recursivamente para os primeiros n-1 elementos
    recursiveBubbleSort(arr, n - 1);
}
Enter fullscreen mode Exit fullscreen mode

4. Odd-Even Sort (Brick Sort)

Variação que compara elementos em posições ímpares/pares alternadamente.

void oddEvenSort(int arr[], int n) {
    bool isSorted = false;

    while (!isSorted) {
        isSorted = true;

        // Compara elementos em posições ímpares
        for (int i = 1; i <= n - 2; i += 2) {
            if (arr[i] > arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                isSorted = false;
            }
        }

        // Compara elementos em posições pares
        for (int i = 0; i <= n - 2; i += 2) {
            if (arr[i] > arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                isSorted = false;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Exercícios Práticos

Exercício 1: Implementação Básica

Implemente o Bubble Sort para ordenar um array de strings por ordem alfabética.

💡 Solução do Exercício 1

#include 
#include 
using namespace std;

// Função para trocar duas strings
void swapStrings(string arr[], int pos1, int pos2) {
    cout &lt;&lt; "  -&gt; Trocando \"" &lt;&lt; arr[pos1] &lt;&lt; "\" com \"" &lt;&lt; arr[pos2] &lt;&lt; "\"" &lt;&lt; endl;
    string temp = arr[pos1];
    arr[pos1] = arr[pos2];
    arr[pos2] = temp;
}

// Bubble Sort para strings
void bubbleSortStrings(string arr[], int size) {
    cout &lt;&lt; "Ordenando strings por ordem alfabética usando Bubble Sort:" &lt;&lt; endl;

    for (int i = 0; i &lt; size - 1; i++) {
        cout &lt;&lt; "\n&gt;&gt;&gt; ITERAÇÃO " &lt;&lt; (i + 1) &lt;&lt; " &lt;&lt;&lt;" &lt;&lt; endl;
        bool hasSwapped = false;

        for (int j = 0; j &lt; size - i - 1; j++) {
            cout &lt;&lt; "Comparando \"" &lt;&lt; arr[j] &lt;&lt; "\" com \"" &lt;&lt; arr[j + 1] &lt;&lt; "\"";

            if (arr[j] &gt; arr[j + 1]) {
                cout &lt;&lt; " -&gt; \"" &lt;&lt; arr[j] &lt;&lt; "\" &gt; \"" &lt;&lt; arr[j + 1] &lt;&lt; "\", precisa trocar!" &lt;&lt; endl;
                swapStrings(arr, j, j + 1);
                hasSwapped = true;
            } else {
                cout &lt;&lt; " -&gt; \"" &lt;&lt; arr[j] &lt;&lt; "\" &lt;= \"" &lt;&lt; arr[j + 1] &lt;&lt; "\", sem troca" &lt;&lt; endl;
            }
        }

        cout &lt;&lt; "Array após iteração " &lt;&lt; (i + 1) &lt;&lt; ": ";
        for (int k = 0; k &lt; size; k++) {
            if (k &gt;= size - i - 1) {
                cout &lt;&lt; "[\"" &lt;&lt; arr[k] &lt;&lt; "\"] ";
            } else {
                cout &lt;&lt; "\"" &lt;&lt; arr[k] &lt;&lt; "\" ";
            }
        }
        cout &lt;&lt; endl;

        if (!hasSwapped) {
            cout &lt;&lt; "Nenhuma troca realizada - array já está ordenado!" &lt;&lt; endl;
            break;
        }
    }
}

int main() {
    const int SIZE = 6;
    string nomes[SIZE] = {"Maria", "João", "Ana", "Pedro", "Carlos", "Beatriz"};

    cout &lt;&lt; "Array inicial: ";
    for (int i = 0; i &lt; SIZE; i++) {
        cout &lt;&lt; "\"" &lt;&lt; nomes[i] &lt;&lt; "\" ";
    }
    cout &lt;&lt; endl &lt;&lt; endl;

    bubbleSortStrings(nomes, SIZE);

    cout &lt;&lt; "\n========================================" &lt;&lt; endl;
    cout &lt;&lt; "RESULTADO FINAL:" &lt;&lt; endl;
    cout &lt;&lt; "Array ordenado: ";
    for (int i = 0; i &lt; SIZE; i++) {
        cout &lt;&lt; "\"" &lt;&lt; nomes[i] &lt;&lt; "\" ";
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; "========================================" &lt;&lt; endl;

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Exercício 2: Bubble Sort com Contador de Operações

Modifique o algoritmo Bubble Sort para contar e exibir o número total de comparações e trocas realizadas.

💡 Solução do Exercício 2

#include 
using namespace std;

struct BubbleSortStats {
    int comparisons;
    int swaps;
    int iterations;
};

void bubbleSortWithStats(int arr[], int size, BubbleSortStats&amp; stats) {
    stats.comparisons = 0;
    stats.swaps = 0;
    stats.iterations = 0;

    cout &lt;&lt; "Bubble Sort com estatísticas detalhadas:" &lt;&lt; endl;

    for (int i = 0; i &lt; size - 1; i++) {
        stats.iterations++;
        cout &lt;&lt; "\n&gt;&gt;&gt; ITERAÇÃO " &lt;&lt; stats.iterations &lt;&lt; " &lt;&lt;&lt;" &lt;&lt; endl;
        bool hasSwapped = false;

        for (int j = 0; j &lt; size - i - 1; j++) {
            stats.comparisons++;
            cout &lt;&lt; "Comparação " &lt;&lt; stats.comparisons &lt;&lt; ": " &lt;&lt; arr[j] &lt;&lt; " vs " &lt;&lt; arr[j + 1];

            if (arr[j] &gt; arr[j + 1]) {
                // Realizar troca
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;

                stats.swaps++;
                hasSwapped = true;
                cout &lt;&lt; " -&gt; Troca " &lt;&lt; stats.swaps &lt;&lt; " realizada!" &lt;&lt; endl;
            } else {
                cout &lt;&lt; " -&gt; Sem troca necessária" &lt;&lt; endl;
            }
        }

        cout &lt;&lt; "Array após iteração " &lt;&lt; stats.iterations &lt;&lt; ": ";
        for (int k = 0; k &lt; size; k++) {
            cout &lt;&lt; arr[k] &lt;&lt; " ";
        }
        cout &lt;&lt; endl;

        if (!hasSwapped) {
            cout &lt;&lt; "Otimização: Array já ordenado, parando antecipadamente!" &lt;&lt; endl;
            break;
        }
    }
}

int main() {
    int numeros[] = {64, 34, 25, 12, 22, 11, 90};
    int tamanho = sizeof(numeros) / sizeof(numeros[0]);
    BubbleSortStats estatisticas;

    cout &lt;&lt; "Array inicial: ";
    for (int i = 0; i &lt; tamanho; i++) {
        cout &lt;&lt; numeros[i] &lt;&lt; " ";
    }
    cout &lt;&lt; endl;

    bubbleSortWithStats(numeros, tamanho, estatisticas);

    cout &lt;&lt; "\n========================================" &lt;&lt; endl;
    cout &lt;&lt; "ESTATÍSTICAS FINAIS:" &lt;&lt; endl;
    cout &lt;&lt; "Iterações realizadas: " &lt;&lt; estatisticas.iterations &lt;&lt; endl;
    cout &lt;&lt; "Total de comparações: " &lt;&lt; estatisticas.comparisons &lt;&lt; endl;
    cout &lt;&lt; "Total de trocas: " &lt;&lt; estatisticas.swaps &lt;&lt; endl;
    cout &lt;&lt; "Array final: ";
    for (int i = 0; i &lt; tamanho; i++) {
        cout &lt;&lt; numeros[i] &lt;&lt; " ";
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; "========================================" &lt;&lt; endl;

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Exercício 3: Bubble Sort Bidirecional (Cocktail Sort)

Implemente uma variação do Bubble Sort que funciona nas duas direções.

💡 Solução do Exercício 3

#include 
using namespace std;

void cocktailSort(int arr[], int size) {
    cout &lt;&lt; "Implementando Cocktail Sort (Bubble Sort Bidirecional):" &lt;&lt; endl;

    bool hasSwapped = true;
    int start = 0;
    int end = size - 1;
    int iteration = 0;

    while (hasSwapped) {
        iteration++;
        hasSwapped = false;

        cout &lt;&lt; "\n&gt;&gt;&gt; ITERAÇÃO " &lt;&lt; iteration &lt;&lt; " - DIREÇÃO →" &lt;&lt; endl;
        // Passada da esquerda para direita
        for (int i = start; i &lt; end; i++) {
            cout &lt;&lt; "Comparando " &lt;&lt; arr[i] &lt;&lt; " com " &lt;&lt; arr[i + 1];
            if (arr[i] &gt; arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                hasSwapped = true;
                cout &lt;&lt; " -&gt; Trocado!" &lt;&lt; endl;
            } else {
                cout &lt;&lt; " -&gt; Sem troca" &lt;&lt; endl;
            }
        }

        if (!hasSwapped) {
            break;
        }

        end--;

        cout &lt;&lt; "\n&gt;&gt;&gt; ITERAÇÃO " &lt;&lt; iteration &lt;&lt; " - DIREÇÃO ←" &lt;&lt; endl;
        // Passada da direita para esquerda
        for (int i = end; i &gt; start; i--) {
            cout &lt;&lt; "Comparando " &lt;&lt; arr[i] &lt;&lt; " com " &lt;&lt; arr[i - 1];
            if (arr[i] &lt; arr[i - 1]) {
                swap(arr[i], arr[i - 1]);
                hasSwapped = true;
                cout &lt;&lt; " -&gt; Trocado!" &lt;&lt; endl;
            } else {
                cout &lt;&lt; " -&gt; Sem troca" &lt;&lt; endl;
            }
        }

        start++;

        cout &lt;&lt; "Array após iteração " &lt;&lt; iteration &lt;&lt; ": ";
        for (int j = 0; j &lt; size; j++) {
            cout &lt;&lt; arr[j] &lt;&lt; " ";
        }
        cout &lt;&lt; endl;
    }
}

int main() {
    int numeros[] = {5, 1, 4, 2, 8, 0, 2};
    int tamanho = sizeof(numeros) / sizeof(numeros[0]);

    cout &lt;&lt; "Array inicial: ";
    for (int i = 0; i &lt; tamanho; i++) {
        cout &lt;&lt; numeros[i] &lt;&lt; " ";
    }
    cout &lt;&lt; endl;

    cocktailSort(numeros, tamanho);

    cout &lt;&lt; "\nArray final ordenado: ";
    for (int i = 0; i &lt; tamanho; i++) {
        cout &lt;&lt; numeros[i] &lt;&lt; " ";
    }
    cout &lt;&lt; endl;

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Exercício 4: Análise de Performance

Compare o desempenho do Bubble Sort com e sem otimização de parada antecipada.

🤔 Desafio Extra

Implemente uma versão do Bubble Sort que:

  1. Conta operações (comparações e trocas)
  2. Para automaticamente quando detecta que está ordenado
  3. Mostra estatísticas detalhadas no final
  4. Funciona com diferentes tipos de dados (int, float, string)

🏆 Solução do Desafio Extra

#include <iostream>
#include <string>
#include <vector>
#include <chrono>
#include <iomanip>
using namespace std;
using namespace std::chrono;

// Estrutura para armazenar estatísticas de ordenação
struct SortingStats {
    int comparisons = 0;
    int swaps = 0;
    int iterations = 0;
    double timeElapsed = 0.0;
    bool optimizedExit = false;
};

// Template para Bubble Sort genérico com estatísticas
template<typename T>
void advancedBubbleSort(T arr[], int size, SortingStats& stats) {
    auto start = high_resolution_clock::now();

    cout << "\n========================================" << endl;
    cout << "ADVANCED BUBBLE SORT WITH STATISTICS" << endl;
    cout << "========================================" << endl;

    stats = {0, 0, 0, 0.0, false}; // Reset statistics

    cout << "Array inicial: ";
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl << endl;

    bool hasSwapped = true;

    while (hasSwapped && stats.iterations < size - 1) {
        hasSwapped = false;
        stats.iterations++;

        cout << ">>> ITERAÇÃO " << stats.iterations << " <<<" << endl;

        for (int i = 0; i < size - stats.iterations; i++) {
            stats.comparisons++;

            cout << "Comparação " << stats.comparisons << ": " 
                 << arr[i] << " vs " << arr[i + 1];

            if (arr[i] > arr[i + 1]) {
                // Realizar troca
                T temp = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = temp;

                stats.swaps++;
                hasSwapped = true;
                cout << " -> Troca " << stats.swaps << " realizada!" << endl;
            } else {
                cout << " -> Sem troca necessária" << endl;
            }
        }

        cout << "Estado do array: ";
        for (int i = 0; i < size; i++) {
            if (i >= size - stats.iterations) {
                cout << "[" << arr[i] << "] ";
            } else {
                cout << arr[i] << " ";
            }
        }
        cout << endl;

        if (!hasSwapped) {
            stats.optimizedExit = true;
            cout << "🎯 OTIMIZAÇÃO: Array já ordenado! Parando antecipadamente." << endl;
        }
        cout << "--------------------------------" << endl;
    }

    auto end = high_resolution_clock::now();
    auto duration = duration_cast<microseconds>(end - start);
    stats.timeElapsed = duration.count() / 1000.0; // Convert to milliseconds

    cout << "\n========================================" << endl;
    cout << "ESTATÍSTICAS DETALHADAS" << endl;
    cout << "========================================" << endl;
    cout << "Elementos no array: " << size << endl;
    cout << "Iterações realizadas: " << stats.iterations << endl;
    cout << "Total de comparações: " << stats.comparisons << endl;
    cout << "Total de trocas: " << stats.swaps << endl;
    cout << "Tempo de execução: " << fixed << setprecision(3) 
         << stats.timeElapsed << " ms" << endl;
    cout << "Otimização ativada: " << (stats.optimizedExit ? "✅ Sim" : "❌ Não") << endl;
    cout << "Eficiência: " << fixed << setprecision(2) 
         << ((double)stats.swaps / stats.comparisons * 100) << "% das comparações resultaram em trocas" << endl;

    cout << "\nArray final ordenado: ";
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
    cout << "========================================" << endl;
}

// Função para testar com diferentes tipos de dados
void testWithIntegers() {
    cout << "\n🔢 TESTE COM NÚMEROS INTEIROS" << endl;
    int numeros[] = {64, 34, 25, 12, 22, 11, 90};
    int tamanho = sizeof(numeros) / sizeof(numeros[0]);
    SortingStats stats;

    advancedBubbleSort(numeros, tamanho, stats);
}

void testWithFloats() {
    cout << "\n🔢 TESTE COM NÚMEROS DECIMAIS" << endl;
    float decimais[] = {3.14f, 2.71f, 1.41f, 1.73f, 0.57f};
    int tamanho = sizeof(decimais) / sizeof(decimais[0]);
    SortingStats stats;

    advancedBubbleSort(decimais, tamanho, stats);
}

void testWithStrings() {
    cout << "\n📝 TESTE COM STRINGS" << endl;
    string nomes[] = {"Maria", "João", "Ana", "Pedro", "Carlos"};
    int tamanho = sizeof(nomes) / sizeof(nomes[0]);
    SortingStats stats;

    advancedBubbleSort(nomes, tamanho, stats);
}

void testWithAlreadySorted() {
    cout << "\n✅ TESTE COM ARRAY JÁ ORDENADO (Demonstração de Otimização)" << endl;
    int ordenado[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int tamanho = sizeof(ordenado) / sizeof(ordenado[0]);
    SortingStats stats;

    advancedBubbleSort(ordenado, tamanho, stats);
}

void testWithReverseSorted() {
    cout << "\n❌ TESTE COM ARRAY INVERSAMENTE ORDENADO (Pior Caso)" << endl;
    int reverso[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
    int tamanho = sizeof(reverso) / sizeof(reverso[0]);
    SortingStats stats;

    advancedBubbleSort(reverso, tamanho, stats);
}

// Função para comparar performance
void performanceComparison() {
    cout << "\n📊 COMPARAÇÃO DE PERFORMANCE" << endl;
    cout << "=============================" << endl;

    // Teste com diferentes tamanhos
    vector<int> sizes = {5, 10, 15};

    for (int size : sizes) {
        cout << "\n🔍 Testando com " << size << " elementos:" << endl;

        // Criar array aleatório
        int* arr = new int[size];
        for (int i = 0; i < size; i++) {
            arr[i] = rand() % 100;
        }

        SortingStats stats;
        advancedBubbleSort(arr, size, stats);

        cout << "Resultado: " << stats.iterations << " iterações, " 
             << stats.comparisons << " comparações, " 
             << stats.swaps << " trocas em " 
             << stats.timeElapsed << " ms" << endl;

        delete[] arr;
    }
}

int main() {
    cout << "==================================================" << endl;
    cout << "BUBBLE SORT AVANÇADO - DESAFIO EXTRA COMPLETO" << endl;
    cout << "==================================================" << endl;

    // Teste com diferentes tipos de dados
    testWithIntegers();
    testWithFloats();
    testWithStrings();

    // Testes especiais para demonstrar otimizações
    testWithAlreadySorted();
    testWithReverseSorted();

    // Comparação de performance
    performanceComparison();

    cout << "\n🎉 Todos os testes foram concluídos com sucesso!" << endl;
    cout << "📚 Este exemplo demonstra:" << endl;
    cout << "   ✅ Contagem de operações" << endl;
    cout << "   ✅ Parada antecipada (otimização)" << endl;
    cout << "   ✅ Estatísticas detalhadas" << endl;
    cout << "   ✅ Suporte a diferentes tipos de dados" << endl;
    cout << "   ✅ Medição de tempo de execução" << endl;
    cout << "   ✅ Análise de eficiência" << endl;

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Explicação da Solução

Esta solução avançada implementa todos os requisitos do desafio:

1. Contagem de Operações
  • Struct SortingStats armazena comparações, trocas, iterações e tempo
  • Cada operação é contada e exibida em tempo real
2. Parada Antecipada
  • Flag hasSwapped detecta quando não há mais trocas
  • Para automaticamente, economizando iterações desnecessárias
3. Estatísticas Detalhadas
  • Número total de operações realizadas
  • Tempo de execução em milissegundos
  • Percentual de eficiência (trocas/comparações)
  • Indicação se a otimização foi ativada
4. Suporte a Diferentes Tipos
  • Template genérico funciona com int, float, string
  • Testes demonstram funcionamento com cada tipo
5. Recursos Extras
  • Visualização do processo de ordenação
  • Testes com casos especiais (já ordenado, inverso)
  • Comparação de performance com diferentes tamanhos
  • Medição precisa de tempo de execução

Esta implementação é ideal para estudos avançados de algoritmos e análise de performance!


Conclusão

O Bubble Sort é um algoritmo fundamental para aprender os conceitos de ordenação devido à sua simplicidade conceitual e facilidade de implementação. Embora não seja eficiente para arrays grandes, é excelente para fins educacionais e situações específicas onde a estabilidade é crucial.

O algoritmo demonstra claramente os conceitos de:

  • Comparação de elementos adjacentes
  • Algoritmos estáveis vs. instáveis
  • Otimizações algorítmicas (parada antecipada)
  • Análise de complexidade no melhor e pior caso
  • Trade-offs entre simplicidade e eficiência

Quando usar Bubble Sort:

  • Arrays muito pequenos (< 10 elementos)
  • Situações educacionais
  • Quando a estabilidade é essencial
  • Como base para entender algoritmos mais complexos

Top comments (2)

Collapse
 
bruno_freschi_097efd99fd6 profile image
Bruno Freschi

Que post massa, conteúdo muito bom!

Collapse
 
mrpunkdasilva profile image
Mr Punk da Silva • Edited

Obrigado mano

Tenho outros conteúdos se quiser dar uma olhada, espero que tenha sido útil!