Как преобразовать направленный ациклический граф (DAG) в дерево - PullRequest
14 голосов
/ 09 марта 2009

Я искал примеры C # для преобразования DAG в дерево.

У кого-нибудь есть примеры или указатели в правильном направлении?

Обновление уточнений

У меня есть график, который содержит список модулей, которые требуется загрузить моему приложению. У каждого модуля есть список модулей, от которых он зависит. Например, вот мои модули, A, B C, D и E

  • A не имеет зависимостей
  • B зависит от A, C и E
  • C зависит от A
  • D зависит от A
  • E зависит от C и A

Я хочу разрешить зависимости и создать дерево, которое выглядит следующим образом ...

- A

- + - B

----- + - C

--------- + - D

- + - Е

Топологическая сортировка

Спасибо за информацию, если я выполню топологическую сортировку и переверну вывод, у меня будет следующий порядок

  • A
  • B
  • C
  • D

Я хочу сохранить иерархическую структуру, чтобы мои модули загружались в правильном контексте, например ... модуль E должен находиться в том же контейнере, что и B

Спасибо

Rohan

Ответы [ 5 ]

20 голосов
/ 13 июля 2009

Есть теоретический ответ на график и ответ программиста на это. Я полагаю, вы сами справитесь с программистами. Для графа теоретический ответ:

  • DAG - это набор модулей, в которых никогда не бывает так, что A нужен B, и в то же время B (или одному из модулей B) нужен A, говоря по модулям: циклическая зависимость отсутствует. Я видел циклические зависимости (ищите примеры на форумах Gentoo), так что вы даже не можете быть на 100% уверены, что у вас есть DAG, но давайте предположим, что у вас есть. Если проверка циклических зависимостей не очень сложная, я бы порекомендовал сделать это где-нибудь в загрузчике модулей.
  • В дереве никогда не может произойти то, что A зависит от B и C, а B и C зависят от D (ромба), но это может происходить в DAG.
  • Кроме того, дерево имеет ровно один корневой узел, но группа обеспечения доступности баз данных может иметь несколько «корневых» узлов (т. Е. Модулей, от которых ничего не зависит). Например, такая программа, как GIMP, программа GIMP будет корневым узлом набора модулей, но для GENTOO почти любая программа с графическим интерфейсом является «корневым» узлом, а библиотеки и т. Д. Являются их зависимостями. (То есть Konqueror и Kmail зависят от Qtlib, но ничего не зависит от Konqueror и ничего не зависит от Kmail)

Теоретический ответ Графа на ваш вопрос, как указывали другие, заключается в том, что DAG нельзя преобразовать в дерево, в то время как каждое дерево является DAG.

Однако (программисты высокого уровня отвечают), если вам нужно дерево для графических представлений, вас интересуют только зависимости конкретного модуля, а не то, что зависит от этого модуля. Позвольте мне привести пример:

A depends on B and C
B depends on D and E
C depends on D and F

Я не могу показать это как дерево ASCII-искусства, по той простой причине, что это не может быть преобразовано в дерево. Однако, если вы хотите показать, от чего зависит A, вы можете показать это:

A
+--B
|  +--D
|  +--E
+--C
   +--D
   +--F

Как видите, вы получаете двойные записи в своем дереве - в данном случае «только» D, но если вы сделаете «развернуть все» в дереве Gentoo, я гарантирую вам, что ваше дерево будет иметь как минимум 1000-кратную сумму узлов, так как есть модули. (есть как минимум 100 пакетов, которые зависят от Qt, поэтому все, от чего зависит Qt, будет присутствовать в дереве как минимум 100 раз).

Если у вас есть «большое» или «сложное» дерево, может быть лучше развернуть дерево динамически, а не заранее, в противном случае у вас может быть процесс, требующий очень большой памяти.

Недостаток дерева выше в том, что если вы нажмете кнопку open B, то D, вы увидите, что A и B зависят от D, но не то, что C также зависит от D. Однако, в зависимости от вашей ситуации, это может быть важно вообще - если вы поддерживаете список загруженных модулей, при загрузке C вы видите, что вы уже загрузили D, и не важно, что он был загружен не для C, а для B. Он загружен, вот и все вопросы. Если вы динамически поддерживаете то, что напрямую зависит от определенного модуля, вы можете решить и противоположную проблему (выгрузку).

Однако то, что вы не можете сделать с деревом, это то, что в вашем последнем предложении: сохранить топологический порядок, то есть, если B загружается в тот же контейнер, что и C, вы никогда не загрузите C в тот же контейнер, что и Что ж. Или вам, возможно, придется смириться с тем, чтобы все было помещено в один контейнер (хотя я не совсем понимаю, что вы имеете в виду под «загрузкой в ​​один контейнер»)

Удачи!

4 голосов
/ 09 марта 2009

DAG и дерево - это не одно и то же математически. Таким образом, любое преобразование вносит неоднозначность. Дерево по определению не имеет циклов, точка.

2 голосов
/ 09 марта 2009

То, что вы ищете, чтобы найти порядок загрузки ваших модулей, это Топологическая сортировка вашего DAG. Если ребра переходят от модуля к модулям, от которых он зависит (что, я думаю, наиболее вероятно), вам придется загружать модули в порядке, обратном топологической сортировке, потому что модуль появится, прежде чем все модули от которого это зависит.

Если вы представляете DAG так, что ребра переходят от зависимых модулей к зависимым от них модулям (вы можете получить это путем обращения всех ребер на графике выше), вы можете просто загрузить модули в порядке топологического рода.

1 голос
/ 09 марта 2009

Многое зависит от того, как вы представляете свой DAG. Например, это может быть матрица смежности (A [i, j] = 1, если есть ребро от узла i к узлу j, иначе 0), или как система указателей, или как массив узлов и массив края ....

Кроме того, не ясно, какое преобразование вы пытаетесь применить. Подключенный DAG - это дерево, поэтому, боюсь, вам нужно немного прояснить свой вопрос.

0 голосов
/ 09 марта 2009

Это можно сделать только в том случае, если все поддеревья имеют один корневой узел.

...