我有以下问题,我有一个类似它的文件:
1 2
1 3
2 4
2 5
6 7
6 8
9 1
每个数字代表网络的“节点”。左节点与右节点连接,如果它们连接,则它们属于同一“集群”。
我想找到这些数字和群集组成所产生的“群集”的数量,在这种情况下应该给出输出:
cluster[1]=(1,2,3,4,5,9)
cluster[2]=(6,7,8)
我认为为每个号码添加标签可能很有用,每次我找到这个号码的邻居或邻居的邻居时,它都会采用相同的标签(然后就是“第n”号码)在集群向量cluster[n]
)中,如果有一个数字不属于任何过去的集群,那么它需要一个新的标签等..但我不知道如何在代码中重现这个想法。有什么帮助吗?
答案 0 :(得分:2)
如上所述,您应该使用Graph。您正在寻找无向图的连通组件。
#!/usr/bin/env perl
use strict;
use warnings;
use Graph::Undirected;
my $g = Graph::Undirected->new(unionfind => 1);
while (my $line = <DATA>) {
last unless $line =~ /\A ([0-9]+) \s+ ([0-9]+) \s+ \z/x;
$g->add_edge($1, $2);
}
my @cc = sort { @$b <=> @$a }
map { [ sort @$_ ] } $g->connected_components;
printf "[%s]\n", join(', ', @$_) for @cc;
__DATA__
1 2
1 3
2 4
2 5
6 7
6 8
9 1
[1, 2, 3, 4, 5, 9] [6, 7, 8]
答案 1 :(得分:1)
my @node_links = (
{a => 1, b => 2},
{a => 1, b => 3},
);
my %clusters;
for my $node_link (@node_links) {
$clusters{ $node_link->{a} } ||= {};
$clusters{ $node_link->{a} }->{ $node_link->{$b} } = 1;
$clusters{ $node_link->{b} } ||= {};
$clusters{ $node_link->{b} }->{ $node_link->{$a} } = 1;
}
my @clusters;
while (my($node, $node_links) = each %clusters) {
my %cluster;
$cluster{$node} = 1;
delete $clusters{$node};
build_cluster(\%clusters, \%cluster, $node_links);
push(@clusters, \%cluster);
}
sub build_cluster {
my($clusters, $cluster, $node_links) = @_;
for my $node (keys %$node_links) {
$cluster->{$node} = 1;
if ($clusters->{$node}) {
my $next_node_links = delete $clusters->{$node};
build_cluster($clusters, $cluster, $next_node_links);
}
}
}
答案 2 :(得分:0)
除了此处提供的解决方案,您还可以使用Graph::UnionFind解决此问题。我认为最近我问过a question可能有帮助,因为它为同样的问题提供了很好的解决方案。