如何在Perl中找到图形的连通组件?

时间:2010-10-28 14:56:38

标签: linux perl unix graph

我有以下节点和边缘集合。我想要做的是从中找到所有不同的图形。

my %connections=(36=>[31],10=>[3,4],31=>[30,22],30=>[20],22=>[20,8],20=>[1],8=>[5],5=>[2],2=>[1,20],  3=>[7]);

在这个例子中,它将产生:

my %all_graph = {
   graph1 => {36=>[31],31=>[30,22],30=>[20],22=>[20,8],20=>[1],8=>[5],5=>[2],2=>[1,20]}.
   graph2  => {10=>[3,4],  3=>[7]} 
};

是否有任何现有算法可以做到这一点? alt text

3 个答案:

答案 0 :(得分:9)

使用Graph模块:

#!/usr/bin/perl

use strict; use warnings;

use Graph;

my %connections = (
    36 => [ 31 ],
    10 => [ 3, 4],
    31 => [ 30, 22],
    30 => [ 20 ],
    22 => [ 20, 8],
    20 => [ 1 ],
    8  => [ 5 ],
    5  => [ 2 ],
    2  => [ 1, 20 ],
    3  => [ 7 ]
);

my $g = Graph->new( undirected => 1 );

for my $src ( keys %connections ) {
    for my $tgt ( @{ $connections{$src} } ) {
        $g->add_edge($src, $tgt);
    }
}

my @subgraphs = $g->connected_components;
my @allgraphs;

for my $subgraph ( @subgraphs ) {
    push @allgraphs, {};
    for my $node ( @$subgraph ) {
        if ( exists $connections{ $node } ) {
            $allgraphs[-1]{$node} = [ @{ $connections{$node} } ];
        }
    }
}

use YAML; print Dump \@allgraphs;

输出:

[sinan@archardy SO]$ ./g
---
- 2:
    - 1
    - 20
  20:
    - 1
  22:
    - 20
    - 8
  30:
    - 20
  31:
    - 30
    - 22
  36:
    - 31
  5:
    - 2
  8:
    - 5
- 10:
    - 3
    - 4
  3:
    - 7

答案 1 :(得分:3)

要查找无向图的连通分量,您只需执行BFS或DFS(宽度/深度优先搜索)。

这里有一些BFS代码示例

my %connections=(36=>[31],10=>[3,4],31=>[30,22],30=>[20],22=>[20,8]
                ,20=>[1],8=>[5],5=>[2],2=>[1,20],  3=>[7]);
my $full_connections = {}; # Build a REAL graph with full 2-way edge lists
foreach my $node (keys %connections) {
    foreach my $node2 (@{ $connections{$node} }) {
        print "$node, $node2\n";
        $full_connections->{$node}->{$node2} = 1;
        $full_connections->{$node2}->{$node} = 1;
    }
}

my %all_graph = ();
my $current_graph = 0;
my %visited = ();
my @to_visit = ();
foreach my $node (keys %$full_connections) {
    next if exists $visited{$node};
    # start the next segment
    $current_graph++;
    @to_visit=($node);
    while (@to_visit) {
        $node_to_visit = shift @to_visit;
        #next if $visited{$node_to_visit};
        $visited{$node_to_visit} = $current_graph;
        push @to_visit, grep { !exists $visited{$_} }
                              keys %{ $full_connections->{$node_to_visit} };
    }
}

# Now reconstruct %all_graph from %visited - left as exercise for the reader
print Data::Dumper->Dump([\%visited]);

答案 2 :(得分:1)

我建议使用以下算法:

1。)将所有节点移动到工作集N

2。)从任意节点开始执行图搜索(depth-firstbreadth-first)。将所有访问过的节点和边添加到第一个子图,从N

中删除访问过的节点

3.如果N非空,请选择下一个起始节点并转到步骤2.)以获取下一个子图。