Как построить в Java взвешенный направленный ациклический граф

Я искал похожие темы, но ответы слишком расплывчаты для моего уровня понимания и понимания, и я не думаю, что они достаточно конкретны для моего вопроса.

Похожие темы:
Реализация дерева (направленный ациклический граф)
Представление DAG (направленный ациклический граф)

Вопрос:

Я отформатировал текстовый файл, содержащий данные в следующем формате ...
Пример набора данных:
GO: 0000109 # is_a: GO: 0000110 # is_a: GO: 0000111 # is_a: GO: 0000112 # is_a : GO: 0000113 # is_a: GO: 0070312 # is_a: GO: 0070522 # is_a: GO: 0070912 # is_a: GO: 0070913 # is_a: GO: 0071942 # part_of: GO: 0008622
GO: 0000112 # part_of: GO: 0000442
GO: 0000118 # is_a: GO: 0016581 # is_a: GO: 0034967 # is_a: GO: 0070210 # is_a: GO: 0070211 # is_a: GO: 0070822 # is_a: GO: 0070823 # is_a: GO : 0070824
GO: 0000120 # is_a: GO: 0000500 # is_a: GO: 0005668 # is_a: GO: 0070860
GO: 0000123 # is_a: GO: 0005671 # is_a: GO: 0043189 # is_a: GO : 0070461 # is_a: GO: 0070775 # is_a: GO: 0072487
GO: 0000126 # is_a: GO: 0034732 # is_a: GO: 0034733
GO: 0000127 # part_of: GO: 0034734 # part_of: GO : 0034735
GO: 0000133 # is_a: GO: 0031560 # is_a: GO: 0031561 # is_a: GO: 0031562 # is_a: GO: 0031563 # part_of: GO: 0031500
GO: 0000137 # part_of: GO : 0000136

Я хочу построить взвешенный направленный DAG из этих данных (приведенное выше - это всего лишь фрагмент). Полный набор данных размером 106 КБ находится здесь: Источник

--------------------------------------------------

По очереди данные каждой строки объясняются следующим образом ...
Первая строка в качестве примера:
GO: 0000109 # is_a: GO: 0000110 # is_a: GO: 0000111 #is_a: GO: 0000112 # is_a: GO: 0000113 # is_a: GO: 0070312 # is_a: GO: 0070522 # is_a: GO: 0070912 # is_a: GO: 0070913 # is_a: GO: 0071942 # part_of: GO: 0008622

'#' - это разделитель / токенизатор для строковых данных.
Первый член, GO: 0000109 - это имя узла.
Последующие термины is_a: GO: xxxxxxx OR part_of: GO: xxxxxxx являются узлы, которые подключены к GO: 0000109.
Некоторые из последующих терминов также имеют связи, как показано в наборе данных.
Когда это is_a, вес ребра равен 0,8.
Когда это part_of, вес ребра 0,6.

--------------------------------------------------

У меня есть Google-d о том, каковы DAG, и я понимаю эту концепцию. Однако я до сих пор не знаю, как это воплотить в коде. Я использую Java.
Насколько я понимаю, граф обычно состоит из узлов и дуг. Требуется ли для этого графа список смежности для определения направления соединения? Если да, то я не уверен, как объединить граф и список смежности для взаимодействия друг с другом. После построения графа моя вторичная цель - выяснить степень каждого узла от корневого узла. В наборе данных есть корневой узел.

Для иллюстрации я нарисовал образец подключения первой строки данных ниже:
Ссылка на изображение

Надеюсь, вы понимаете, чего я здесь пытаюсь достичь. Спасибо, что рассмотрели мою проблему. :)


person bumper_boy2000    schedule 15.12.2011    source источник


Ответы (2)


Читая комментарии, вы, кажется, сбиты с толку тем, как узел может содержать отношения, каждое из которых, в свою очередь, содержит узел. Это довольно распространенная стратегия, ее в целом называют шаблоном Composite.

Идея в случае деревьев состоит в том, что дерево можно представить как состоящее из нескольких поддеревьев - если бы вы отключили узел и всех его предков от дерева, отключенные узлы все равно составили бы дерево, хотя и меньшего размера. Таким образом, естественный способ представления дерева - сделать так, чтобы каждый узел содержал другие узлы в качестве дочерних. Этот подход позволяет вам делать многие вещи рекурсивно, что в случае с деревьями часто, опять же, естественно.

Разрешение узлу отслеживать своих дочерних элементов и никаких других частей дерева также имитирует математический ориентированный граф - каждая вершина «осведомлена» только о своих ребрах и ни о чем другом.

Пример реализации рекурсивного дерева

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

Аналогично, чтобы добавить новый узел в дерево, вы должны вызвать метод add корневого узла с новым узлом в качестве параметра. Корень решает, следует ли ему принять новый узел или передать его одному из своих дочерних узлов. В последнем случае он выберет дочерний элемент и вызовет его метод добавления с новым узлом в качестве параметра.

person Emil Lundberg    schedule 20.12.2011
comment
ах. было бы правильно сказать, что для построения дерева единственный способ - это рекурсивное построение из листа? - person bumper_boy2000; 20.12.2011
comment
Это не единственный способ, но, безусловно, распространенный, многие программисты находят рекурсивные алгоритмы привлекательно элегантными. Однако я считаю, что дерево проще построить из корня, чем из листьев. См. Мой отредактированный ответ. - person Emil Lundberg; 20.12.2011
comment
хорошо. Дизайн рекурсивных методов - одна из моих слабых сторон, но я буду работать над этим как хорошее обучение! : D спасибо Эмиль! - person bumper_boy2000; 20.12.2011

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

У вас может быть класс Node, который будет иметь коллекцию дочерних Node объектов. При необходимости вы также можете представить дочерние отношения как объект Relationship, который будет иметь как вес, так и указатель Node, и вы можете сохранить коллекцию объектов Relationship.

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

class Node{
    String name;
    List<Relationship> children;
}

class Relationship{
    Node child;
    double weight;
}

class Tree{
    Node root;
}

Здесь Tree, вероятно, должен иметь такой метод:

public Node findNodeByName(String name);

И Node, вероятно, должен иметь такой метод:

public void addChild(Node n, double weight);

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

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

person Community    schedule 15.12.2011
comment
не могли бы вы помочь мне с вашим предложением, предоставив какой-то псевдокод вашей реализации? : / - person bumper_boy2000; 15.12.2011
comment
хорошо ... учитывая, что узел называется VNode. как насчет дуг? - person bumper_boy2000; 15.12.2011
comment
о, хорошо, я пропустил роль addchild. так что на самом деле дуги не нужно делать как класс / объект? - person bumper_boy2000; 15.12.2011
comment
Класс Relationship будет представлять края. - person ; 16.12.2011
comment
Хорошо, я в тупике, как Node имеет список отношений, в то время как Relationship имеет VNode как свойство. аааааааааааааааааааааааааа! я не могу представить, как построить, хотя я могу понять, как запросить из графа, если он был завершен. : / - person bumper_boy2000; 19.12.2011
comment
несколько родителей, несколько детей. :( - person bumper_boy2000; 19.12.2011
comment
Не несколько родителей - каждый узел будет иметь только одного родителя (исключение: у корня не будет родителя), но может иметь любое количество потомков. Кроме того, каждый узел знает только о своих дочерних элементах и ​​не обращает внимания на своего родителя. - person Emil Lundberg; 20.12.2011