【问题标题】:How to build in Java a Weighted Directed Acyclic Graph如何在 Java 中构建加权有向无环图
【发布时间】:2012-01-20 23:27:52
【问题描述】:

我搜索了类似的主题,但答案对于我的理解和理解水平来说太模糊了,而且我认为它们对我的问题不够具体。

类似线程:
Tree (directed acyclic graph) implementation
Representing a DAG (directed acyclic graph)

问题:

我已经格式化了一个包含以下格式数据的文本文件...
示例数据集:
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
去:0000126#is_a:去:0034732#is_a:去: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(上面只是一个 sn-p)。 106kb的整个数据集在这里:Source

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

逐行考虑,每行数据解释如下...
以第一行为例:
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。

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

我有关于 DAG 的 Google-d,我理解这个概念。但是,我仍然不知道如何将其放入代码中。我正在使用 Java。
据我了解,图通常由节点和弧组成。这个图是否需要邻接表来确定连接的方向?如果是这样,我不确定如何结合图形和邻接表来相互通信。 构建完图后,我的次要目标是从根节点中找出每个节点的度数。数据集中有一个根节点。

为了说明,我在下面画出了第一行数据的连接示例:
Image Link

我希望你们理解我在这里想要实现的目标。感谢您浏览我的问题。 :)

【问题讨论】:

    标签: java directed-acyclic-graphs weighted


    【解决方案1】:

    因为它更容易思考,所以我更愿意将它表示为一棵树。 (也更容易遍历地图并保持中间度数。)

    你可以有一个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 不能真正转换为树,尤其是因为某些节点有多个父节点。您可以做的是插入与多个父节点的子节点相同的节点,可能使用哈希表来确定是否已遍历特定节点。

    【讨论】:

    • 您能否通过提供某种实现的伪代码来帮助我提出您的建议? ://
    • ok...考虑到一个节点称为VNode。弧线怎么样?
    • 哦,好吧,我错过了 addchild 的部分。所以实际上弧不需要作为类/对象制作?
    • Relationship 类将表示边缘。
    • 好吧,我对 Node 有一个关系列表感到困惑,而一个关系有一个 VNode 作为属性。啊啊啊!我无法想象如何构建,尽管我可以弄清楚如何从图表中查询它是否已完成。 ://
    【解决方案2】:

    阅读 cmets,您似乎对节点如何包含关系而感到困惑,而每个关系又包含一个节点。这是一种很常见的策略,通常称为复合模式。

    在树的情况下的想法是,树可以被认为是由多个子树组成的 - 如果您要断开一个节点及其所有祖先与树的连接,断开连接的节点仍然会形成一棵树,尽管较小的一个。因此,表示树的一种自然方式是让每个节点包含其他节点作为子节点。这种方法可以让你递归地做很多事情,这在树的情况下通常是自然的。

    让一个节点跟踪它的子节点,而不是树的其他部分,这也模拟了数学有向图——每个顶点只“知道”它的边,而没有其他任何东西。

    递归树实现示例

    例如,要在二叉搜索树中搜索元素,您可以调用根的搜索方法。然后根检查寻找的元素是否等于、小于或大于自身。如果相等,则搜索以适当的返回值退出。如果它小于或大于,根会分别调用左子或右子的搜索,它们会做完全相同的事情。

    类似地,要将新节点添加到树中,您可以调用根的 add 方法,并将新节点作为参数。根决定它是应该采用新节点还是将其传递给它的一个子节点。在后一种情况下,它将选择一个子节点并以新节点作为参数调用其 add 方法。

    【讨论】:

    • 啊。是不是说为了构造树,唯一的方法就是从叶子递归构造?
    • 这不是唯一的方法,但绝对是一种常见的方法,许多程序员发现递归算法非常优雅。但是,我认为从根而不是叶子构建树更容易。请参阅我编辑的答案。
    • 好的。递归方法设计是我的弱点之一,但我会努力训练它! :D 谢谢埃米尔!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 2012-12-22
    相关资源
    最近更新 更多