in reply to connected component
Last time I needed to do this, which was a few years ago, I ended up rolling my own, because anything I could find in CPAN was too slow. This may have changed since then, but an algorithm for this is not difficult; see the attached code.
use strict; use warnings; package Graph; sub new { my $self = bless +{}, shift; $self->build( @_ ); return $self; } sub build { my $self = shift; my ( $nodes, $edges ) = @_; sanity_check( $nodes, $edges ); my %nodes = map +( $_ => Node->new( $_ ) ), @$nodes; for my $edge ( @$edges ) { my @nodes = @nodes{ @$edge }; $nodes[ 0 ]->add_neighbor( $nodes[ 1 ] ); } $self->{ nodes } = \%nodes; return; } sub sanity_check { # just ensures that all edges refer to nodes in the given # node set; the graph may contain isolated nodes. my $nodes_hash = { map +( $_ => 1 ), @{ shift() } }; for my $edge ( @{ shift() } ) { defined $nodes_hash->{ $_ } || die "Unknown node: $_\n" for @$edge; } return; } sub connected_components { my $self = shift; my @components; my %visited; for my $node ( values %{ $self->{ nodes } } ) { next if defined $visited{ $node->{ id } }; push @components, $node->component; $visited{ $_ } = 1 for keys %{ $components[ -1 ] }; } return [ map [ keys %$_ ], @components ]; } package Node; sub new { my $self = bless +{}, shift; $self->{ id } = shift; return $self; } sub add_neighbor { my $self = shift; my $neighbor = shift; $self->{ neighbors }{ $neighbor->{ id } } = $neighbor; $neighbor->{ neighbors }{ $self->{ id } } = $self; return; } sub component { my $self = shift; my $component = shift || +{}; $component->{ $self->{ id } } = $self; for my $neighbor ( grep !defined $component->{ $_->{ id } }, values %{ $self->{ neighbors } } ) { $neighbor->component( $component ); } return $component; } package main; my $n_nodes = 25; my $max_edges = 15; my $r = sub { 1 + int(rand $n_nodes) }; my $nodes = [ 1..$n_nodes ]; my $edges = [ map [ $r->(), $r->() ], 1..$max_edges ]; print "@$_\n" for @{ Graph->new( $nodes, $edges )->connected_components() }; __END__ 6 11 7 17 8 4 1 18 21 15 19 16 2 22 25 23 5 10 13 3 9 12 20 14 24
the lowliest monk
|
|---|