Pular para o conteúdo

Estruturas de Dados e Algoritmos

Todo programa faz duas coisas: guarda dados e resolve problemas com eles. Estruturas de dados e algoritmos são os nomes para essas duas metades, e é a dupla que decide se o seu código responde em milissegundos ou trava quando os dados crescem.

Uma estrutura de dados é uma forma de organizar e guardar dados para facilitar o acesso e a modificação deles. Pense na diferença entre uma pilha de livros no chão e uma estante organizada por autor. Os livros são os mesmos, mas achar um título específico é bem mais rápido na estante. Por outro lado, empilhar um livro novo no chão é mais rápido do que achar o lugar certo na estante.

Esse é o ponto principal: cada estrutura deixa algumas operações baratas e outras caras. Não existe uma estrutura melhor em tudo, existe a que combina com o que o seu programa mais faz.

Alguns exemplos que você já usa: arrays, objetos e Map do JavaScript. Nas notas seguintes você vai ver como eles funcionam por dentro.

Um algoritmo é uma sequência finita de passos bem definidos que recebe uma entrada e produz uma saída, resolvendo um problema. A receita de bolo serve de novo: os ingredientes são a entrada, os passos são o algoritmo e o bolo é a saída.

Algoritmo e estrutura de dados andam sempre juntos. O algoritmo é o que você faz, a estrutura é onde os dados estão enquanto você faz.

Dois programas podem dar a mesma resposta e ainda assim ter custos muito diferentes. Um exemplo: achar um usuário pelo id.

// Com uma lista: percorre até achar
const usuarioNaLista = usuarios.find((u) => u.id === id);
// Com um Map indexado por id: vai direto
const usuarioNoMap = usuariosPorId.get(id);

Com 100 usuários, ninguém percebe a diferença. Com um milhão, o find pode olhar até um milhão de itens a cada requisição, enquanto o Map faz uma quantidade praticamente constante de trabalho. Multiplique isso pelo número de requisições por segundo e a diferença vira servidor a mais, ou site fora do ar.

O custo de um algoritmo aparece em três lugares:

  • tempo de execução: quanto demora
  • uso de memória: quanto espaço ocupa
  • escalabilidade: como os dois crescem quando os dados aumentam

Aqui “escalabilidade” é o custo do código crescer devagar conforme os dados crescem. O lado de infraestrutura (mais servidores, load balancer, cache) está na seção de Escalabilidade, e as duas conversam: às vezes, trocar um algoritmo é mais barato do que comprar uma máquina maior.

Um código que “funciona” passou nos testes de hoje, com poucos dados. Um código que “funciona bem” continua funcionando quando os dados crescem 100 vezes. Conhecer as estruturas e os algoritmos clássicos ajuda de três formas:

  • você escreve código mais eficiente sem esforço extra, porque já sabe qual ferramenta cabe em cada caso
  • você toma decisões de arquitetura com base em custo, e não em palpite. Um exemplo é o índice de banco de dados, que existe justamente para o banco não varrer a tabela inteira a cada consulta
  • você resolve problemas novos com mais facilidade, porque eles quase sempre são variações de problemas clássicos
NotaO que você vai ver
Complexidade e Big OA régua para medir e comparar o custo de um algoritmo
Estruturas LinearesArray, lista ligada, pilha e fila
Tabelas HashChave e valor com acesso rápido
ÁrvoresDados hierárquicos, busca em ordem e heap
GrafosConexões entre coisas, BFS e DFS
Recursão, Busca e OrdenaçãoOs algoritmos mais clássicos
Paradigmas de ProjetoDivisão e conquista, programação dinâmica, guloso e backtracking
Padrões de ResoluçãoTwo pointers, sliding window e como reconhecer o formato do problema