Ordenación topológica con DFS en postorden
Ejecute DFS y apile cada nodo después de explorar por completo sus vecinos; después, desapile para obtener un orden topológico válido.
Ordenación topológica con DFS en postorden es una lección gratuita de Coding Interview Prep en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Coding Interview Prep, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Coding Interview Prep incluye 4 lecciones en total.
Idea del ordenamiento topológico basado en DFS
El segundo algoritmo clásico de ordenamiento topológico utiliza DFS con procesamiento en postorden. Después de explorar por completo todos los vecinos de un nodo (y sus descendientes), inserte el nodo en una pila. Cuando se hayan procesado todos los nodos, extraiga los elementos de la pila para obtener el orden topológico. Que un nodo se inserte en la pila después de todas sus dependencias significa que aparece primero en el orden, por lo que el postorden invertido es el ordenamiento topológico.
Intuición del postorden
Considere un grafo de dependencias en el que el curso A requiere el curso B. Cuando DFS visita A, primero recurre en B. B no tiene prerrequisitos, por lo que termina primero y se inserta primero en la pila. Después termina A y se inserta en la pila. Al extraer la pila, se obtiene A antes que B en la salida, pero al final invertimos el resultado y obtenemos B antes que A: tome primero B y después A. El postorden inserta las dependencias antes que los elementos dependientes, por lo que la pila invertida es un orden topológico válido.
DFS de tres colores para detectar ciclos
Utilice tres estados para los nodos visitados: WHITE (0) = sin visitar, GREY (1) = en proceso (en la pila de llamadas de DFS), BLACK (2) = procesado por completo. Una arista de retroceso —una arista hacia un nodo GREY— indica que existe un ciclo. Las aristas hacia nodos BLACK son seguras, ya que esos nodos ya se exploraron por completo. Este esquema de tres colores detecta correctamente todos los ciclos en grafos dirigidos.
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)Implementación completa del ordenamiento topológico con DFS
Utilice un DFS recursivo que coloree los nodos, los inserte en una pila en postorden y devuelva False al detectar un ciclo. Después de visitar todos los nodos, la pila invertida proporciona el orden topológico.
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 el desbordamiento de la pila
El límite de recursión de Python (1000 de forma predeterminada) puede ser un problema en grafos grandes. Un DFS iterativo que utilice una pila explícita evita este problema. El truco consiste en insertar inicialmente (node, False); al extraerlo con False, inserte (node, True) (lo que significa «volveré aquí después de explorar») y, después, inserte todos los vecinos no visitados con False. Al extraerlo con True, coloréelo de BLACK e insértelo en la pila 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 frente a Kahn: comparación
Ambos algoritmos se ejecutan en O(V + E). Diferencias principales: Kahn (BFS) produce naturalmente los nodos en un orden que prioriza las dependencias más tempranas y ofrece una detección de ciclos más sencilla (mediante la comprobación de la longitud). El postorden de DFS funciona de forma recursiva y detecta explícitamente las aristas de retroceso. Se prefiere Kahn cuando se desea el resultado en orden directo, sin invertirlo. Se prefiere DFS cuando se necesita el postorden completo para otros fines, como la detección de SCC. Ambos métodos son aceptables en entrevistas.
Postorden en un árbol frente a un DAG
En un árbol, el postorden visita el subárbol izquierdo → el subárbol derecho → la raíz. En un DAG, el DFS en postorden visita todas las dependencias de un nodo antes de procesar el propio nodo: es la misma idea generalizada a múltiples predecesores y a una estructura de grafo arbitraria. La raíz de un árbol de DFS (el nodo inicial) se inserta después que todos sus descendientes, por lo que aparece primero en la pila invertida: la posición topológica correcta para un nodo sin predecesores.
Alien Dictionary (LeetCode 269)
Alien Dictionary: dada una lista ordenada de palabras de un idioma alienígena, deduzca el orden de sus caracteres. Compare las palabras adyacentes carácter por carácter para encontrar la primera diferencia; esto proporciona una arista c1 → c2, que significa que c1 aparece antes que c2. Reúna todas esas aristas y ejecute un ordenamiento topológico para obtener el orden de los caracteres alienígenas. Si existe un ciclo, el orden no es válido.
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'Ordenamiento topológico con restricciones
Algunos problemas solicitan un ordenamiento topológico que cumpla restricciones adicionales, como mantener el orden relativo de los elementos de la lista original. Combine el algoritmo de Kahn con una cola de prioridad personalizada o con un ordenamiento previo: conserve el orden relativo original mediante un ordenamiento estable del contenido de la cola en cada paso. Estas variantes con restricciones ponen a prueba una comprensión más profunda de la flexibilidad del algoritmo.
Reconocimiento de problemas de ordenamiento topológico
Algunas frases indicadoras en problemas de entrevistas que apuntan al ordenamiento topológico son: «dadas las dependencias», «prerrequisitos», «orden de las tareas», «orden de compilación», «¿se pueden completar todas las tareas?», «encuentre una secuencia válida». Si el problema implica ordenar elementos de modo que algunos deban aparecer antes que otros, construya un grafo dirigido y aplique el ordenamiento topológico de Kahn o de DFS. La detección de ciclos suele ser un requisito adicional del mismo problema.
Comparación de las salidas de DFS y Kahn
DFS y Kahn pueden producir órdenes topológicos válidos diferentes para el mismo grafo. Ambos son correctos: un DAG puede tener varios órdenes topológicos válidos. Para verificar la corrección, compruebe que, para cada arista u → v del grafo, u aparezca antes que v en el orden de salida. En problemas de entrevistas que exigen un orden específico (por ejemplo, el lexicográficamente menor), utilice Kahn con un montículo mínimo; el postorden de DFS no produce naturalmente el orden lexicográficamente menor.
Comprobación rápida
Ponga a prueba su comprensión de los conceptos de Data Structures & Algorithms — Coding Interview Prep de esta lección.
Resumen de la lección
En esta lección aprendió que: el ordenamiento topológico mediante el postorden de DFS inserta los nodos después de explorar todas sus dependencias, el marcado con tres colores (WHITE/GREY/BLACK) detecta ciclos mediante aristas de retroceso hacia nodos GREY y al invertir la pila del postorden se obtiene un orden topológico válido. A continuación aplicaremos directamente el ordenamiento topológico a los problemas Course Schedule I y II.
Preguntas frecuentes
¿La lección «Ordenación topológica con DFS en postorden» es gratis?
Sí — el texto completo de «Ordenación topológica con DFS en postorden» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Coding Interview Prep, actualiza a CoddyKit PRO. El curso de Coding Interview Prep incluye 4 lecciones en total.
¿Qué aprenderé en «Ordenación topológica con DFS en postorden»?
Ejecute DFS y apile cada nodo después de explorar por completo sus vecinos; después, desapile para obtener un orden topológico válido. Practicas Coding Interview Prep con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Coding Interview Prep?
No se requiere experiencia previa. Coding Interview Prep en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Ordenación topológica con DFS en postorden»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Coding Interview Prep?
Sí. Cada lección de Coding Interview Prep incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Algoritmo de Kahn: ordenación topológica con BFS
- Ordenación topológica con DFS en postorden
- Course Schedule I y II
- Componentes fuertemente conexas con Kosaraju