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

Obrigado mano

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