Я ищу простой алгоритм для «сериализации» ориентированного графа. В частности, у меня есть набор файлов с взаимозависимостями в порядке их выполнения, и я хочу найти правильный порядок во время компиляции. Я знаю, что это должно быть довольно обычное дело - компиляторы делают это постоянно, - но мой гугл-фу сегодня был слабым. Какой для этого нужно алгоритм?





Я бы ожидал, что инструменты, которым это нужно, просто пройдут дерево в глубину, и когда они попадут в лист, просто обработайте его (например, скомпилируйте) и удалите его из графа (или отметьте его как обработанный, и обработайте узлы всеми листьями обрабатывается как листья).
Пока это DAG, этот простой обход на основе стека должен быть тривиальным.
Я придумал довольно наивный рекурсивный алгоритм (псевдокод):
Map<Object, List<Object>> source; // map of each object to its dependency list
List<Object> dest; // destination list
function resolve(a):
if (dest.contains(a)) return;
foreach (b in source[a]):
resolve(b);
dest.add(a);
foreach (a in source):
resolve(a);
Самая большая проблема заключается в том, что он не может обнаруживать циклические зависимости - он может перейти в бесконечную рекурсию (т.е. переполнение стека ;-p). Единственный способ обойти это, что я вижу, - это превратить рекурсивный алгоритм в интерактивный с ручным стеком и вручную проверить стек на наличие повторяющихся элементов.
У кого-нибудь есть что-нибудь получше?
вместо foreach используйте while, поддерживайте два указателя, просматривающих данные a: ведущий, который выполняет двойные шаги, а конечный, который выполняет одиночные шаги. Ведущий указатель обрабатывает фактические разрешения, и если он когда-либо переходит конечный указатель, возникает цикл.
Топологическая сортировка (из Википедии):
In graph theory, a topological sort or topological ordering of a directed acyclic graph (DAG) is a linear ordering of its nodes in which each node comes before all nodes to which it has outbound edges. Every DAG has one or more topological sorts.
Псевдокод:
L ← Empty list where we put the sorted elements
Q ← Set of all nodes with no incoming edges
while Q is non-empty do
remove a node n from Q
insert n into L
for each node m with an edge e from n to m do
remove edge e from the graph
if m has no other incoming edges then
insert m into Q
if graph has edges then
output error message (graph has a cycle)
else
output message (proposed topologically sorted order: L)
Эх ... скопировал прямо с википедии?
Спасибо. Помог мне сопоставить тот факт, что дерево зависимостей можно отсортировать с помощью этого метода. :-)
Если график содержит циклы, как могут существовать разрешенные порядки выполнения для ваших файлов? Мне кажется, что если в графике есть циклы, то у вас нет решения, а это сообщается правильно вышеуказанным алгоритмом.
Да, топологическая сортировка невозможна, если граф содержит циклы. Это соответствует реальному миру: если я попрошу вас сделать A перед B, и B перед A, вы не сможете меня удовлетворить ;-).
Да, вот как ты это делаешь. Это называется поиском в глубину (DFS). И если вы не уверены, что у вас есть DAG, вы должны проверить задние края, иначе цикл отправит вас в бесконечный цикл.