Pular para o conteúdo

Algoritmos e estruturas de dados · Grafos · 7 min de leitura

Grafos: busca em largura (BFS) e em profundidade (DFS)

Redes sociais, mapas, dependências de build: tudo é grafo. A BFS acha o caminho com menos arestas usando uma fila; a DFS explora até o fim usando uma pilha ou recursão.

A → B1A → C2B → D3C → D: já vistojá vistoD → E4A — nível 0Anível 0B — nível 1Bnível 1C — nível 1Cnível 1D — nível 2Dnível 2E — nível 3Enível 3

Arraste para o lado para ver o diagrama inteiro.

A BFS descobre B e C (passos 1 e 2) antes de ir mais longe. D é alcançado por B (passo 3); quando chega a vez de C, D já foi visto e não entra de novo na fila.

Como representar

Um grafo tem vértices (pessoas, cidades, módulos) e arestas (amizade, estrada, dependência), com ou sem direção e peso. A forma mais comum é a lista de adjacência: um mapa de cada vértice para seus vizinhos. Matriz de adjacência (V × V) só compensa em grafos densos.

BFS: em largura

Usa uma fila e um conjunto de visitados. Visita todos os vizinhos antes de ir mais longe, então a primeira vez que alcança um vértice é pelo menor número de arestas — caminho mais curto em grafo sem peso (labirintos, "graus de separação"). Com pesos, use Dijkstra (heap) no lugar.

DFS: em profundidade

Usa uma pilha (ou recursão) e vai até o fim de um caminho antes de voltar. Serve para achar ciclos, componentes conectados, ordenação topológica (em que ordem compilar módulos ou rodar migrations) e resolver labirintos. Em grafos grandes, prefira a pilha explícita para não estourar a pilha de chamadas.

No código

✓ ExemploKotlin
// Menor número de passos de 'origem' até 'destino' (ou -1 se não há caminho)
fun distancia(grafo: Map<String, List<String>>, origem: String, destino: String): Int {
    val fila = ArrayDeque(listOf(origem))
    val dist = hashMapOf(origem to 0) // também serve de "visitados"
    while (fila.isNotEmpty()) {
        val v = fila.removeFirst()
        if (v == destino) return dist.getValue(v)
        for (viz in grafo[v].orEmpty()) {
            if (viz !in dist) {
                dist[viz] = dist.getValue(v) + 1
                fila.addLast(viz)
            }
        }
    }
    return -1
}

Marcar o vértice ao enfileirar (e não ao tirar da fila) evita que ele entre duas vezes. Cada vértice e cada aresta são vistos uma vez: O(V + E).

Em resumo

Exercícios

Responda e confira na hora. Complexidades valem com ou sem espaços, como O(n log n).

  1. Qual busca encontra o caminho com menos arestas num grafo sem pesos: BFS ou DFS?

    Ver a solução

    Resposta: BFS. A BFS visita por níveis, então chega a cada vértice pela menor quantidade de arestas.

  2. Qual estrutura auxiliar a BFS usa: pilha ou fila?

    Ver a solução

    Resposta: fila. A fila garante que os vértices mais próximos (descobertos antes) sejam visitados primeiro.

  3. Qual a complexidade da BFS com lista de adjacência, para V vértices e E arestas?

    Ver a solução

    Resposta: O(V + E). Cada vértice entra na fila uma vez (V) e cada aresta é examinada uma vez (E, ou 2E se não dirigido).

Vantagens e custos

Vantagens
  • BFS garante o caminho mais curto em arestas.
  • DFS usa pouca memória em grafos profundos e estreitos.
  • As duas são simples e lineares no tamanho do grafo.
Custos e riscos
  • BFS guarda um nível inteiro na fila (muita memória em grafos largos).
  • DFS recursiva pode estourar a pilha.
  • Nenhuma das duas considera pesos: aí entra Dijkstra.

Perguntar à IA

Monte um prompt pronto sobre Grafos: busca em largura (BFS) e em profundidade (DFS) na sua linguagem e no seu caso, e abra num chat gratuito.

ChatGPT Claude Perplexity

O prompt vai para o site que você escolher. Não cole senhas, tokens nem dados reais de clientes. Para Gemini e outros, copie e cole.

Referências

Continue aprendendo

Todos os temas de algoritmos e estruturas de dados →