DEV Community

Matheus Sena
Matheus Sena

Posted on

1

Entendendo Big O: Como Avaliar a Eficiência de um Algoritmo

Image description

Como podemos medir o quanto complexo é um algoritmo?
Vamos explorar o que é o Big O, uma notação usada para descrever a eficiência dos algoritmos, com exemplos do mundo real e implementações em Java para facilitar o entendimento.

O Que é Big O? 🤔

Big O é uma notação matemática usada para descrever a eficiência de um algoritmo, particularmente em termos de tempo de execução (tempo necessário para executar o algoritmo) ou uso de memória (quantidade de memória necessária).

Ou seja, à medida que o tamanho da entrada (n) aumenta, o Big O nos ajuda a entender como o algoritmo se comporta.

Exemplo do Mundo Real 🛒

Vamos usar uma analogia simples do mundo real: você está em uma livraria com uma lista de livros. Imagine que você deseja encontrar um livro específico nessa lista. Existem duas maneiras principais de fazer isso:

  1. Busca Sequencial: Você começa no topo da lista e verifica cada livro na estante até encontrar o que está procurando.
  2. Lista Ordenada: Imagine que a lista está ordenada alfabeticamente. Você pode usar uma busca mais eficiente para encontrar o item.

Aplicando o Conceito de Big O 🧠

  1. Busca Sequencial (O(n)): Este método verifica cada item um por um. Se houver n itens na lista, no pior caso, você precisará verificar todos os n itens. Portanto, o tempo de execução cresce linearmente com o tamanho da lista. Isso é representado como O(n).

  2. Busca Binária em Lista Ordenada (O(log n)): Se a lista estiver ordenada, você pode realizar uma busca binária, que divide a lista pela metade a cada passo. O tempo de execução cresce logaritmicamente, o que é muito mais rápido para listas grandes. Isso é representado como O(log n).

Exemplos em Java 🖥️

1. Busca Linear (O(n)) 🚶

Este é o exemplo de uma busca linear, onde verificamos cada elemento da lista até encontrar o que estamos procurando.

public class BuscaLinear {
    public static int buscar(int[] array, int valor) {
        for (int i = 0; i < array.length; i++) {
            if (array[i] == valor) {
                return i; // Retorna o índice do valor
            }
        }
        return -1; // Retorna -1 se não encontrar
    }

    public static void main(String[] args) {
        int[] numeros = {10, 20, 30, 40, 50};
        int indice = buscar(numeros, 30);
        System.out.println("Encontrado no índice: " + indice);
    }
}
Enter fullscreen mode Exit fullscreen mode

Neste exemplo, o tempo de execução depende diretamente do tamanho da lista. Se a lista tiver 1000 elementos, pode ser necessário verificar todos eles no pior caso.

2. Busca Binária (O(log n)) 🚀

Se a lista estiver ordenada, podemos usar a busca binária para encontrar o elemento de forma mais eficiente.

import java.util.Arrays;

public class BuscaBinaria {
    public static int buscar(int[] array, int valor) {
        int inicio = 0;
        int fim = array.length - 1;

        while (inicio <= fim) {
            int meio = (inicio + fim) / 2;
            if (array[meio] == valor) {
                return meio;
            } else if (array[meio] < valor) {
                inicio = meio + 1;
            } else {
                fim = meio - 1;
            }
        }
        return -1; // Retorna -1 se não encontrar
    }

    public static void main(String[] args) {
        int[] numeros = {10, 20, 30, 40, 50};
        Arrays.sort(numeros); // Certifica-se de que o array está ordenado
        int indice = buscar(numeros, 30);
        System.out.println("Encontrado no índice: " + indice);
    }
}
Enter fullscreen mode Exit fullscreen mode

Aqui, a busca binária divide a lista pela metade em cada iteração, permitindo que você encontre o item desejado muito mais rapidamente do que na busca linear.

Tipos Comuns de Big O

1. O(1) - Tempo Constante

O tempo de execução é constante e não depende do tamanho da entrada.

Exemplo de Mundo Real: Acender uma luz em uma sala. O tamanho da sala não afeta o tempo que leva para acender a luz.

Exemplo em Java:

public class ExemploO1 {
    public static void main(String[] args) {
        int[] numeros = {10, 20, 30, 40, 50};
        int primeiroNumero = numeros[0]; // O(1)
        System.out.println("Primeiro número: " + primeiroNumero);
    }
}
Enter fullscreen mode Exit fullscreen mode

2. O(n) - Tempo Linear 🚶

O tempo de execução cresce linearmente com o tamanho da entrada.

Exemplo de Mundo Real: Percorrer um corredor reto em uma biblioteca. Quanto maior o corredor, mais tempo leva para atravessá-lo.

Exemplo em Java:

public class ExemploOn {
    public static void main(String[] args) {
        int[] numeros = {10, 20, 30, 40, 50};
        int soma = 0;
        for (int numero : numeros) { // O(n)
            soma += numero;
        }
        System.out.println("Soma: " + soma);
    }
}
Enter fullscreen mode Exit fullscreen mode

3. O(log n) - Tempo Logarítmico 📉

O tempo de execução cresce logaritmicamente à medida que a entrada cresce.

Exemplo de Mundo Real: Procurar um nome em um diretório telefônico ordenado, onde a cada etapa você reduz pela metade o número de páginas a serem verificadas.

Exemplo em Java:

import java.util.Arrays;

public class ExemploOlogn {
    public static int buscaBinaria(int[] array, int valor) {
        int inicio = 0;
        int fim = array.length - 1;

        while (inicio <= fim) {
            int meio = (inicio + fim) / 2;
            if (array[meio] == valor) {
                return meio; // Valor encontrado
            } else if (array[meio] < valor) {
                inicio = meio + 1;
            } else {
                fim = meio - 1;
            }
        }
        return -1; // Valor não encontrado
    }

    public static void main(String[] args) {
        int[] numeros = {10, 20, 30, 40, 50};
        Arrays.sort(numeros); // Certifica-se de que o array está ordenado
        int indice = buscaBinaria(numeros, 30); // O(log n)
        System.out.println("Valor encontrado no índice: " + indice);
    }
}
Enter fullscreen mode Exit fullscreen mode

4. O(n^2) - Tempo Quadrático 🏢

O tempo de execução cresce quadraticamente com o tamanho da entrada.

Exemplo de Mundo Real: Uma competição onde cada pessoa deve apertar a mão de todas as outras. Com n pessoas, haverá n * n apertos de mão.

Exemplo em Java:

public class ExemploOn2 {
    public static void main(String[] args) {
        int[] numeros = {64, 25, 12, 22, 11};
        selectionSort(numeros); // O(n^2)
        System.out.println("Array ordenado: ");
        for (int numero : numeros) {
            System.out.print(numero + " ");
        }
    }

    public static void selectionSort(int[] array) {
        int n = array.length;

        for (int i = 0; i < n - 1; i++) {
            int indiceMin = i;
            for (int j = i + 1; j < n; j++) {
                if (array[j] < array[indiceMin]) {
                    indiceMin = j;
                }
            }
            int temp = array[indiceMin];
            array[indiceMin] = array[i];
            array[i] = temp;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

5. O(2^n) - Tempo Exponencial 🌋

O tempo de execução cresce exponencialmente com o tamanho da entrada.

Exemplo de Mundo Real: Tentar adivinhar uma senha de n caracteres onde cada caractere pode ser uma letra ou número. O número de combinações possíveis cresce exponencialmente.

Exemplo em Java:

public class ExemploO2n {
    public static void main(String[] args) {
        int n = 10;
        System.out.println("Fibonacci de " + n + " é " + fibonacci(n)); // O(2^n)
    }

    public static int fibonacci(int n) {
        if (n <= 1) {
            return n;
        }
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusão 🏁

Compreender a complexidade de tempo e a eficiência de um algoritmo é fundamental para otimizar o desempenho do seu código. O Big O fornece uma maneira de descrever como o tempo de execução ou o uso de memória de um algoritmo

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay