Ordenação topológica por pós-ordem de DFS
Execute DFS e empilhe cada nó depois que seus vizinhos forem totalmente explorados; em seguida, desempilhe para obter uma ordem topológica válida.
Ordenação topológica por pós-ordem de DFS é uma aula grátis de DSA Interview Prep no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de DSA Interview Prep, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de DSA Interview Prep inclui 4 aulas no total.
Ideia da ordenação topológica baseada em DFS
O segundo algoritmo clássico de ordenação topológica usa DFS com processamento em pós-ordem. Depois de explorar completamente todos os vizinhos de um nó (e seus descendentes), coloque o nó em uma pilha. Quando todos os nós forem processados, retire os elementos da pilha para ler a ordem topológica. Um nó colocado na pilha depois de todas as suas dependências significa que ele vem primeiro na ordem — portanto, a pós-ordem invertida é a ordenação topológica.
Intuição por trás da pós-ordem
Considere um grafo de dependências em que o curso A exige o curso B. Quando o DFS visita A, primeiro ele faz uma chamada recursiva para B. B não tem pré-requisitos, então termina primeiro e é colocado primeiro na pilha. Em seguida, A termina e é colocado na pilha. Retirar os elementos da pilha fornece A antes de B na saída — mas invertemos no final, obtendo B antes de A: faça B primeiro e depois A. A pós-ordem coloca as dependências antes dos elementos dependentes, portanto, a pilha invertida é uma ordem topológica válida.
DFS de três cores para detecção de ciclos
Use três estados para os nós visitados: WHITE (0) = não visitado, GREY (1) = sendo processado no momento (na pilha de chamadas do DFS), BLACK (2) = totalmente processado. Uma aresta de retorno — uma aresta para um nó GREY — indica um ciclo. As arestas para nós BLACK são seguras (eles já foram explorados completamente). Esse esquema de três cores detecta corretamente todos os ciclos em grafos direcionados.
WHITE, GREY, BLACK = 0, 1, 2
color = [WHITE] * n # n = number of nodes
# During DFS:
# color[node] = GREY (entering node)
# recurse into neighbours
# if neighbour is GREY: cycle found!
# color[node] = BLACK (leaving node, push to stack)Implementação completa da ordenação topológica com DFS
Use um DFS recursivo que atribua cores aos nós, coloque-os em uma pilha em pós-ordem e retorne o valor falso ao detectar um ciclo. Depois de visitar todos os nós, a pilha (invertida) fornece a ordem topológica.
from collections import defaultdict
def dfs_topological_sort(n, edges):
graph = defaultdict(list)
for u, v in edges:
graph[u].append(v)
WHITE, GREY, BLACK = 0, 1, 2
color = [WHITE] * n
stack = []
def dfs(node):
color[node] = GREY
for nxt in graph[node]:
if color[nxt] == GREY:
return False # cycle
if color[nxt] == WHITE:
if not dfs(nxt):
return False
color[node] = BLACK
stack.append(node)
return True
for i in range(n):
if color[i] == WHITE:
if not dfs(i):
return [] # cycle
return stack[::-1]
print(dfs_topological_sort(4, [(0,1),(0,2),(1,3),(2,3)]))DFS iterativo para evitar estouro da pilha
O limite de recursão do Python (1000 por padrão) é uma preocupação para grafos grandes. Um DFS iterativo que usa uma pilha explícita evita esse problema. A técnica é: coloque inicialmente (node, False); quando ele for retirado com False, coloque (node, True) (o que significa “voltarei aqui depois de explorar”) e coloque todos os vizinhos não visitados com o valor falso. Quando for retirado com True, atribua BLACK a ele e coloque-o na pilha de resultados.
from collections import defaultdict
def dfs_topo_iterative(n, edges):
graph = defaultdict(list)
for u, v in edges:
graph[u].append(v)
WHITE, GREY, BLACK = 0, 1, 2
color = [WHITE] * n
result = []
for start in range(n):
if color[start] != WHITE:
continue
stack = [(start, False)]
while stack:
node, returning = stack.pop()
if returning:
color[node] = BLACK
result.append(node)
elif color[node] == WHITE:
color[node] = GREY
stack.append((node, True)) # will return here
for nxt in graph[node]:
if color[nxt] == WHITE:
stack.append((nxt, False))
return result[::-1]DFS versus Kahn: comparação
Ambos executam em O(V + E). Principais diferenças: o algoritmo de Kahn (BFS) produz naturalmente os nós em uma ordem que prioriza primeiro as dependências e tem uma detecção de ciclos mais simples (verificação do tamanho). A pós-ordem do DFS funciona recursivamente e detecta arestas de retorno explicitamente. O algoritmo de Kahn é preferível quando se deseja o resultado na ordem direta, sem inversão. O DFS é preferível quando se precisa da pós-ordem completa para outras finalidades (como detecção de SCC). Ambos são aceitáveis em entrevistas.
Pós-ordem em uma árvore versus um DAG
Em uma árvore, a pós-ordem visita a subárvore esquerda → a subárvore direita → a raiz. Em um DAG, o DFS em pós-ordem visita todas as dependências de um nó antes de processar o próprio nó — a mesma ideia generalizada para vários predecessores e uma estrutura de grafo arbitrária. A raiz de uma árvore de DFS (o nó inicial) é colocada por último entre seus descendentes, fazendo com que apareça primeiro na pilha invertida — a posição topológica correta para um nó sem predecessores.
Dicionário alienígena (LeetCode 269)
Dicionário alienígena: dada uma lista ordenada de palavras em um idioma alienígena, determine a ordenação dos caracteres. Compare palavras adjacentes caractere por caractere para encontrar a primeira diferença — isso fornece uma aresta c1 → c2, significando que c1 vem antes de c2. Colete todas essas arestas e execute uma ordenação topológica para produzir a ordenação dos caracteres alienígenas. Se existir um ciclo, a ordenação será inválida.
from collections import defaultdict
def alienOrder(words):
graph = defaultdict(set)
all_chars = set(c for w in words for c in w)
for i in range(len(words)-1):
w1, w2 = words[i], words[i+1]
if len(w1) > len(w2) and w1.startswith(w2):
return '' # invalid (prefix comes after)
for c1, c2 in zip(w1, w2):
if c1 != c2:
graph[c1].add(c2)
break
# DFS topological sort on character graph
WHITE, GREY, BLACK = 0, 1, 2
color = {c: WHITE for c in all_chars}
result = []
def dfs(c):
color[c] = GREY
for nxt in graph[c]:
if color[nxt] == GREY: return False
if color[nxt] == WHITE and not dfs(nxt): return False
color[c] = BLACK
result.append(c)
return True
for c in all_chars:
if color[c] == WHITE:
if not dfs(c): return ''
return ''.join(result[::-1])
print(alienOrder(['wrt','wrf','er','ett','rftt'])) # 'wertf'Ordenação topológica com restrições
Alguns problemas pedem uma ordenação topológica que satisfaça restrições adicionais, como manter a ordem relativa dos elementos da lista original. Combine o algoritmo de Kahn com uma fila de prioridade personalizada ou uma pré-ordenação: mantenha os elementos na ordem relativa original usando uma ordenação estável no conteúdo da fila a cada etapa. Essas variantes com restrições testam uma compreensão mais profunda da flexibilidade do algoritmo.
Como reconhecer problemas de ordenação topológica
Frases indicativas em problemas de entrevistas que apontam para uma ordenação topológica: “dadas as dependências”, “pré-requisitos”, “ordenação de tarefas”, “ordem de construção”, “é possível concluir todas as tarefas?”, “encontre uma sequência válida”. Se o problema envolver uma ordenação de itens em que alguns devem vir antes de outros, construa um grafo direcionado e aplique o algoritmo de Kahn ou a ordenação topológica com DFS. A detecção de ciclos costuma ser um requisito secundário no mesmo problema.
Comparando as saídas de DFS e Kahn
DFS e Kahn podem produzir ordens topológicas válidas diferentes para o mesmo grafo. Ambas estão corretas — um DAG pode ter várias ordenações topológicas válidas. Para verificar a correção, confira se, para cada aresta u → v no grafo, u aparece antes de v na ordem de saída. Para problemas de entrevistas que exigem uma ordem específica (por exemplo, a ordem lexicograficamente menor), use o algoritmo de Kahn com uma fila de prioridade mínima — a pós-ordem do DFS não produz naturalmente a ordem lexicograficamente menor.
Teste rápido
Teste sua compreensão dos conceitos de Estruturas de Dados & Algoritmos — Preparação para entrevistas de programação desta lição.
Recapitulação da lição
Nesta lição, você aprendeu: a ordenação topológica em pós-ordem com DFS coloca os nós depois que todas as suas dependências são exploradas, a marcação com três cores (WHITE/GREY/BLACK) detecta ciclos por meio de arestas de retorno para nós GREY e inverter a pilha de pós-ordem fornece uma ordenação topológica válida. A seguir, aplicaremos a ordenação topológica diretamente aos problemas Cronograma de cursos I e II.
Perguntas Frequentes
A aula “Ordenação topológica por pós-ordem de DFS” é grátis?
Sim — o texto completo de “Ordenação topológica por pós-ordem de DFS” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de DSA Interview Prep, atualize para CoddyKit PRO. O curso de DSA Interview Prep inclui 4 aulas no total.
O que vou aprender em “Ordenação topológica por pós-ordem de DFS”?
Execute DFS e empilhe cada nó depois que seus vizinhos forem totalmente explorados; em seguida, desempilhe para obter uma ordem topológica válida. Você pratica DSA Interview Prep com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar DSA Interview Prep?
Nenhuma experiência prévia é necessária. DSA Interview Prep no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Ordenação topológica por pós-ordem de DFS”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de DSA Interview Prep?
Sim. Cada aula de DSA Interview Prep inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Algoritmo de Kahn: ordenação topológica por BFS
- Ordenação topológica por pós-ordem de DFS
- Cronograma de cursos I e II
- Componentes fortemente conexos com Kosaraju