2010-10-28 3 views
2

У меня есть ориентированный ациклический граф (дерево), описанный корнями (Parent1 -> Child1), (Parent2 -> Child2), ...., (ParentN -> ChildN). Есть ли какой-либо алгоритм, который восстанавливает дерево (график) из этих данных?Преобразование кортежей в дерево

Лучший пример:

Root 
    Parent1 
    Node1 
     Child1 
     Child2 
    Parent2 
    Node1 
     Child1 
     Child2 

и в качестве входных данных у меня только:

Root -> Parent1 
Node1 -> Child1 
Root -> Parent2 
Parent1 -> Node1 
Parent2 -> Node1 
Node1 -> Child2 

в произвольном порядке.

Имея только эти кортежи, мы можем реконструировать дерево в структуре, как:

Node (имя: String, дети: List)?

+0

Являются ли 'Root.Parent1.Node1' такими же, как' Root.Parent2.Node1'? –

+0

Они одинаково логически, но в дереве они должны быть представлены как повторяющиеся сущности, чьи дети также дублированы. –

+0

Незначительный нит: DAG не обязательно должно быть деревом. Лучше, чтобы вы уточнили, какой адрес вы хотите адресовать, DAG или неориентированное дерево. – srean

ответ

1

Выполните глубину первого обхода начиная с корневого каталога, что позволяет узлам посещать несколько раз (график должен быть ациклическим, конечно, для этого прекратить). Для каждого узла графа, который вы посещаете, вы создаете соответствующий узел дерева и соединяете его с соответствующим деревом узла его родительского графа (edit: Фактически, узел графа может соответствовать нескольким узлам дерева, вас интересует последний).

Например, скажем, ваш корень A:

A 
/\ 
/ \ 
B  C 
    \ /
    \/
    D 

Вы посещаете A, создать tA. Проход идет к B, вы создаете tB, подключите его к tA. Затем вы посетите «D», создать tD, подключить его к tB, то вернуться назад и посетить «C», создать tC и подключить его к tA, так что вы получите это дерево:

tA 
/\ 
/ \ 
tB tC 
| | 
| | 
tD tD' 

Обратите внимание, что вы можете получить экспоненциально большее дерево по сравнению с графиком таким преобразованием.

+0

Да, это было решение, которое я использовал наконец. Спасибо за интерес к моему вопросу и за ваш хороший ответ! –

+0

Рад помочь. Я сказал что-то потенциально обманчивое (см. Править), но, надеюсь, вы не были смущены. –

2

Мне было непонятно, если вы искали структуру данных указателя или нет. Кажется, что вы ищете, так это то, что в конце вы должны иметь возможность перечислять все дочерние узлы узла. Если это требование, то вы можете создать хэш-таблицу (в соответствии с вашим примером, от строки до строки). Затем в вашем файле readline loop задает родительский ключ в хеш-таблице и вектор строк как соответствующее значение. Нажмите на этот вектор. В C++ это будет выглядеть следующим образом

#include <hash_map> 
#include <vector> 
#include <string> 
using namespace std; 
hash_map<string, vector<string>* > graph; 
string parent, child; 

Затем в цикле файл Readline

cin >> parent >> child >> child; 
if (graph[parent] == graph.end()) { 
    graph[parent] = new vector<string>(); 
} 
graph[parent]->push_back(child); 

Remember удалить векторы, как только вы сделали, или использовать auto_ptr.

В псевдокоде:

for every tuple: 
    create HashTable entry with key = tuple.parent 
    HashTable[tuple.parent].addToList(tuple.child) 
+0

Меня больше интересует псевдокод (я программист Java), который строит это дерево с оптимальным количеством операций - возможно, из одной прогулки через входные кортежи. –

+0

@tanderson Java имеет контейнеры HashMap и Vector, поэтому перевод на java должен быть простым. Вышеприведенное решение просматривает входные кортежи только один раз. Если вам не нужен произвольный доступ к разным дочерним узлам узла, вы можете заменить Vector на список. – srean

+0

Я не думаю, что это сработало бы так, как ожидалось: иметь все узлы под Parent1/Node1 и Parent2/Node1, задуманные ... или я что-то упускаю? –

Смежные вопросы