graph:使用包含通配符的节点列表查找子图

时间:2012-02-17 20:49:16

标签: algorithm graph path wildcard

以下问题是否有名称,是否有算法来解决它? : 给定一个图形,无论是有向还是无,找到满足

给出的规范的所有路径
  1. 确切节点列表,或
  2. '*?它表示“任何节点或根本没有节点”或
  3. '* {n}'表示'任意n个连续连接的节点'
  4. e.g。

    A -> B -> *? -> D which results in ABXD and ABYD and ABD etc.
    

    A -> *{1} -> D -> *? -> E which results in ABXDZE and ABYDZE and ABDZE etc. etc.
    

    感谢

    P.S。 有没有人知道在R或perl或C中执行此操作的图形库?

2 个答案:

答案 0 :(得分:1)

我不知道任何图书馆,但你必须将其分为两部分:

  • 用户查询解析
  • 找到您要找的内容的算法

对于解析,我让你找到你需要做的事情(使用解析库或你自己)

关于算法部分,我建议您定义一个特殊结构(如链表)来表示您的查询,其中每个元素可以表示一个真实节点,x个节点或无限数量的节点。

您算法的唯一问题是使用无限数量或有限数量的中间节点查找从节点A到节点B的所有路径。您可以使用动态编程或搜索算法(如DFS或BFS)来执行此操作。

答案 1 :(得分:1)

我最后做的是:

  1. 问题是在2个节点之间找到长度为N的所有路径。不包括周期。
  2. 将数据作为边缘列表读取,例如成对的from->到节点(假定节点的名称是唯一的)
  3. 将节点名称的哈希表(或boost和stl,c ++中的unordered_map)创建为键,将哈希表创建为值。
  4. 此第二个哈希表将包含第一个节点作为键的所有节点。
  5. 例如

    A->B
    A->C
    B->D
    C->E
    E->D
    

    在将所有数据作为'edgelist'读取后,以perl表示法保存输入数据的结果数据结构如下所示:

    my %hash = (
    'A' => {'B' => 1, 'C' => 1},
    'B' => {'D' => 1},
    'C' => {'E' => 1},
    'E' => {'D' => 1},
    );
    

    查找一对节点是否直接连接可以大致完成(perl):

    sub search {
        my ($from,$to) = @_;
        if( $to eq '*' ){ return defined($x=$hash{$from}) ? [keys $hash{$from}] : [] }
        return defined($x=$hash{$from}) && defined($x{$to}) ? [$to] : []
    }
    

    在上面的函数中,通过将$ to设置为'*',可以返回'from'节点所连接的所有节点。返回是直接连接到$ from参数的节点的数组引用。

    搜索两个节点之间的路径需要递归使用上述函数。

    e.g。

    sub path {
        my ($from,$to, $hops, $save_results) = @_;
        if( $hops < 0 ){ return 0 }
        $results = search($from, '*');
        if( "".@$results == 0 ){ return 0 }
        $found = 0;
        foreach $result (@$results){
            $a_node = new Tree::Nary($result);
            if( path($result, $to, $hops-1, $a_node) == 1 ){
                $save_results->insert($save_results, -1, $a_node);
                $found = 1;
            }
        }
        return $found;
    

    }

    如果深度不是太多(即$ hops&lt; 6?),由于堆栈溢出[sic],可以使用递归。

    最棘手的部分是读取结果并提取每个路径的节点。经过大量的考虑,我决定使用Tree :: Nary(n-ary树)来存储结果。最后我们有以下树:

         |-> B -> D
    A -> |-> C -> E -> D
    

    为了提取所有路径,请执行以下操作:

    1. 找到所有叶节点
    2. 从每个叶节点开始,通过其父节点向后移动到根节点并保存节点名称。
    3. 以上是使用perl实现的,但也是在C ++中使用boost :: unordered_map进行哈希表。我还没有在C ++代码中添加树结构。

      结果:对于3281415个边缘和18601个唯一节点,perl需要3分钟才能找到A->'*' - &gt;'*' - > B。我准备好了C ++代码的更新。