Programação & Dev

Algoritmos e Lógica de Programação: O Mapa que Todo Desenvolvedor Precisa

Aprenda a resolver problemas no papel antes de codificar. Entenda sequência, seleção, repetição, algoritmos de ordenação e complexidade Big O.

Algoritmos e Lógica de Programação: O Mapa que Todo Desenvolvedor Precisa

Você não travou porque algoritmos são difíceis. Travou porque ninguém te mostrou o problema antes de te entregar a solução. Esse artigo corrige isso — do conceito mais simples até análise de complexidade.

Essa sensação tem nome — e tem solução. Ela acontece quando você tenta escrever código antes de pensar no algoritmo. É como tentar construir uma casa sem planta: você até levanta algumas paredes, mas logo percebe que o banheiro ficou no lugar errado.

Este artigo vai te mostrar o mapa que todo desenvolvedor precisa dominar antes de digitar a primeira linha de código.

O que é um Algoritmo, de Verdade?

Um algoritmo é simplesmente uma sequência finita e ordenada de passos para resolver um problema. Sem ambiguidade. Sem passos que dependem de adivinhação. Cada instrução precisa ser clara o suficiente para que uma máquina — que não pensa, apenas executa — consiga seguir.

Pense na receita de bolo da sua avó. Ela tem ingredientes (dados de entrada), uma ordem de preparo (passos executáveis) e um resultado esperado (saída). Se você pular um passo ou trocar a ordem, o bolo não sai certo. Com algoritmos, a lógica é exatamente a mesma.

As Três Estruturas que Governam Tudo

Toda a lógica de programação — independente da linguagem — se apoia em apenas três estruturas de controle. Sim, apenas três.

1. Sequência

A mais simples. Os passos são executados um após o outro, na ordem em que aparecem.

C
int x = 10;int y = 20;int soma = x + y;printf("Resultado: %d\n", soma);

Nada de surpresa. O computador lê linha por linha, de cima para baixo.

2. Seleção (Decisão)

Aqui o programa ganha inteligência. Dependendo de uma condição, ele escolhe um caminho ou outro.

C
if (temperatura > 38) {    printf("Febre detectada. Consulte um médico.\n");} else {    printf("Temperatura normal.\n");}

Existem três formas principais de seleção:

  • Simples: um ou dois caminhos alternativos (if/else)

  • Encadeada: escolha entre vários caminhos (if/else if/else)

  • Múltipla: comparar uma variável com vários valores fixos (switch/case)

O switch/case é perfeito quando você tem muitas opções bem definidas — como os dias da semana ou as opções de um menu.

3. Repetição (Laços)

O coração da automação. Executar o mesmo bloco de código várias vezes sem precisar reescrevê-lo.

Repetição contada — quando você sabe exatamente quantas vezes vai repetir:

C
for (int i = 1; i <= 10; i++) {    printf("%d\n", i);}

Repetição com pré-condição — quando você testa a condição antes de entrar no laço:

C
while (saldo > 0) {    saldo -= parcela;}

Repetição com pós-condição — quando o bloco precisa executar pelo menos uma vez:

C
do {    printf("Digite um número positivo: ");    scanf("%d", &numero);} while (numero <= 0);

Tipos de Dados: A Matéria-Prima do Programa

Antes de processar qualquer informação, o computador precisa saber com que tipo de dado está lidando. Em C, os tipos básicos são:

Tipo

O que armazena

Exemplo

int

Números inteiros

42, -7, 0

float

Números com casas decimais

3.14, -0.5

char

Um único caractere

'A', 'z'

char[]

Cadeia de caracteres (texto)

"Olá, mundo"

Esses dados vivem como variáveis (valores que mudam durante a execução) ou constantes (valores que nunca mudam). Usar constantes para valores fixos — como PI = 3.14159 — torna o código mais legível e seguro.

Funções: O Segredo do Código Limpo

Se você se pegar repetindo o mesmo bloco de código em lugares diferentes, é sinal de que aquele trecho merece virar uma função.

Uma função é um bloco de código com um objetivo específico. Ela recebe dados (parâmetros), processa e devolve um resultado.

C
float calcularMedia(float nota1, float nota2, float nota3) {    return (nota1 + nota2 + nota3) / 3;}

Existem dois tipos fundamentais:

  • void: a função executa uma ação e não devolve nada (como imprimir na tela)

  • Tipada (int, float...): a função faz um cálculo e devolve um resultado

Boas Práticas que Fazem Diferença

Dominar a sintaxe é a parte fácil. O que separa um código amador de um código profissional são os hábitos.

Planeje antes de codificar. Antes de abrir o editor, defina: quais dados entram? Quais saem? Qual a sequência de passos? Um rascunho em papel vale mais do que uma hora de tentativa e erro.

Comente o que não é óbvio. O compilador ignora comentários, mas seus colegas (e você mesmo, daqui a seis meses) não. Documente a intenção do código, não apenas o que ele faz.

C
// Calcula o índice de massa corporal conforme tabela da OMSfloat imc = peso / (altura * altura);

Escreva código portável. Evite funções específicas de um sistema operacional quando existir uma alternativa no padrão ISO do C. Código portável roda em Windows, Linux e Unix sem modificações.

Use nomes significativos. temperatura, contador, nomeUsuario são infinitamente melhores que t, c, n. Clareza não é frescura — é respeito pelo próximo que vai ler seu código.

Algoritmos Clássicos que Todo Programador Deve Conhecer

Teoria sem prática é decoração. Veja como os conceitos acima se materializam em algoritmos reais — os mesmos usados em bancos de dados, sistemas de busca e aplicações do dia a dia.

Busca Linear vs. Busca Binária: a diferença que muda tudo

Imagine que você precisa encontrar o número 23 em uma lista de mil números.

Busca Linear — verifica um por um, do início ao fim:

PYTHON
def busca_linear(lista, alvo):    for i in range(len(lista)):        if lista[i] == alvo:            return i  # retorna o índice onde encontrou    return -1  # não encontradonumeros = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]print(busca_linear(numeros, 23))  # saída: 5

Funciona. Mas no pior caso, percorre todos os elementos. Em uma lista de um milhão? Um milhão de comparações.

Busca Binária — divide o problema ao meio a cada passo. Requer lista ordenada:

PYTHON
def busca_binaria(lista, alvo):    inicio = 0    fim = len(lista) - 1    while inicio <= fim:        meio = inicio + (fim - inicio) // 2        if lista[meio] == alvo:            return meio          # encontrou!        elif lista[meio] < alvo:            inicio = meio + 1    # descarta a metade esquerda        else:            fim = meio - 1       # descarta a metade direita    return -1  # não encontradonumeros = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]print(busca_binaria(numeros, 23))  # saída: 5

Algoritmo

Pior caso (1 milhão de itens)

Requer ordenação?

Busca Linear

1.000.000 comparações

Não

Busca Binária

~20 comparações

Sim

Algoritmos de Ordenação: colocando a casa em ordem

Para usar a busca binária, você precisa de dados ordenados. E para ordenar dados, você precisa de um algoritmo de ordenação.

Bubble Sort — o mais simples para entender. Funciona como bolhas subindo à superfície: a cada passagem, o maior elemento flutua para o fim:

PYTHON
def bubble_sort(lista):    n = len(lista)    for i in range(n):        for j in range(0, n - i - 1):            # se o elemento atual é maior que o próximo, troca            if lista[j] > lista[j + 1]:                lista[j], lista[j + 1] = lista[j + 1], lista[j]    return listanumeros = [64, 34, 25, 12, 22, 11, 90]print(bubble_sort(numeros))  # [11, 12, 22, 25, 34, 64, 90]

O mesmo algoritmo em C:

C
void bubble_sort(int arr[], int n) {    for (int i = 0; i < n - 1; i++) {        for (int j = 0; j < n - i - 1; j++) {            if (arr[j] > arr[j + 1]) {                int temp = arr[j];                arr[j] = arr[j + 1];                arr[j + 1] = temp;            }        }    }}

Recursão: quando a função chama a si mesma

Um conceito que assusta iniciantes mas é elegante quando você entende: uma função que resolve um problema chamando a si mesma com uma versão menor do mesmo problema.

PYTHON
def fatorial(n):    # caso base: para a recursão    if n == 0 or n == 1:        return 1    # chamada recursiva com problema menor    return n * fatorial(n - 1)print(fatorial(5))  # 5 × 4 × 3 × 2 × 1 = 120

Toda função recursiva tem dois componentes obrigatórios:

  • Caso base: a condição de parada (sem ela, recursão infinita)

  • Chamada recursiva: o problema reduzido a uma versão menor de si mesmo

Recursão é a base de algoritmos poderosos como Merge Sort, busca em árvores e travessia de grafos.

Complexidade de Algoritmos: o custo do que você escreve

Todo algoritmo tem um custo. A notação Big O descreve como esse custo cresce conforme o tamanho da entrada aumenta.

Notação

Nome

Exemplo

O(1)

Constante

Acessar elemento de array por índice

O(log n)

Logarítmica

Busca Binária

O(n)

Linear

Busca Linear

O(n log n)

Linearítmica

Merge Sort, Quick Sort

O(n²)

Quadrática

Bubble Sort, Selection Sort

O Erro Mais Comum de Quem Está Começando

A maioria dos iniciantes tenta aprender programação aprendendo linguagem.

Decoram a sintaxe do if, do for, do while — mas quando chegam em um problema real, travam. Porque o problema nunca é a sintaxe. O problema é a lógica.

A linguagem é apenas a notação. O algoritmo é o pensamento.

Esse hábito — aparentemente simples — é o que diferencia um programador que avança de um que fica preso eternamente nos tutoriais.

Conclusão

Algoritmos e lógica de programação não são matéria de faculdade. São a base de tudo que você vai construir como desenvolvedor.

Sequência, seleção e repetição. Tipos de dados. Funções bem nomeadas. Busca binária. Complexidade Big O. Planejamento antes do código.

Esses conceitos não saem de moda. Não importa se a linguagem do momento é C, Python, JavaScript ou qualquer outra que surgir nos próximos anos — a lógica por trás de todas elas é a mesma.