我有这个问题:给定了许多数组(例如Perl或任何其他语言):
1. (A,B,C)
2. (B,D,E,F)
3. (C,H,G)
4. (G,H)
在每个数组中,第一个元素是父元素,其余元素是子元素。在这种情况下,元素A有两个子节点B和C,B有三个子节点D,E和F等。我想处理这组数组,并生成一个包含正确顺序的列表。在这种情况下,A是根元素,因此来自B和C,然后在B下是D,E和F,在C下是G和H,G也有H作为子元素(这意味着一个元素可以有多个父元素) )。这应该是结果数组。
重要:看看数组3,H出现在G之前,即使它是第四个数组中G的子节点。因此,每个数组中没有特定的子项顺序,但在最终结果中(如下所示),必须在其子项之前有任何父项。
(A,B,C,D,E,F,G,H)或(A,C,B,D,E,F,G,H)或(A,B,C,G,H, d,E,F)
有一些创建该数组的递归方式会很好,但不是必需的。 谢谢你的时间..
答案 0 :(得分:1)
如果不是节点有多个父节点的可能性,那么这将是一个简单的后序遍历。
要解决此问题,最简单的方法是为每个节点分配层级别。在这种情况下,{3}和第4层都显示H
,并且始终是最高层数。
此代码实现了该设计。
use strict;
use warnings;
my @rules = (
[qw/ A B C / ],
[qw/ B D E F / ],
[qw/ C H G / ],
[qw/ G H / ],
);
# Build the tree from the set of rules
#
my %tree;
for (@rules) {
my ($parent, @kids) = @$_;
$tree{$parent}{$_}++ for @kids;
}
# Find the root node. There must be exactly one node that
# doesn't appear as a child
#
my $root = do {
my @kids = map keys %$_, values %tree;
my %kids = map {$_ => 1} @kids;
my @roots = grep {not exists $kids{$_}} keys %tree;
die qq(Multiple root nodes "@roots" found) if @roots > 1;
die qq(No root nodes found) if @roots < 1;
$roots[0];
};
# Build a hash of nodes versus their tier level using a post-order
# traversal of the tree
#
my %tiers;
my $tier = 0;
traverse($root);
# Build the sorted list and show the result
#
my @sorted = sort { $tiers{$a} <=> $tiers{$b} } keys %tiers;
print "@sorted\n";
sub max {
no warnings 'uninitialized';
my ($x, $y) = @_;
$x > $y ? $x : $y;
}
sub traverse {
my ($parent) = @_;
$tier++;
my @kids = keys %{ $tree{$parent} };
if (@kids) {
traverse($_) for @kids;
}
$tiers{$parent} = max($tiers{$parent}, $tier);
$tier--;
}
<强>输出强>
A B C F E D G H
修改强>
这作为数组的散列稍微干净一些。这是重构。
use strict;
use warnings;
my @rules = (
[qw/ A B C / ],
[qw/ B D E F / ],
[qw/ C H G / ],
[qw/ G H / ],
);
# Build the tree from the set of rules
#
my %tree;
for (@rules) {
my ($parent, @kids) = @$_;
$tree{$parent} = \@kids;
}
# Find the root node. There must be exactly one node that
# doesn't appear as a child
#
my $root = do {
my @kids = map @$_, values %tree;
my %kids = map {$_ => 1} @kids;
my @roots = grep {not exists $kids{$_}} keys %tree;
die qq(Multiple root nodes "@roots") if @roots > 1;
die qq(No root nodes) if @roots < 1;
$roots[0];
};
# Build a hash of nodes versus their tier level using a post-order
# traversal of the tree
#
my %tiers;
traverse($root);
# Build the sorted list and show the result
#
my @sorted = sort { $tiers{$a} <=> $tiers{$b} } keys %tiers;
print "@sorted\n";
sub max {
no warnings 'uninitialized';
my ($x, $y) = @_;
$x > $y ? $x : $y;
}
sub traverse {
my ($parent, $tier) = @_;
$tier //= 1;
my $kids = $tree{$parent};
if ($kids) {
traverse($_, $tier + 1) for @$kids;
}
$tiers{$parent} = max($tiers{$parent}, $tier);
}
输出等同于之前的解决方案,因为有多个正确的排序。请注意,A
始终是第一个,H
是最后一个,A C B F G D E H
是可能的。
答案 1 :(得分:0)
此版本也有效,但它会为您提供所有正确答案的排列,因此您每次都能获得正确的结果,但可能与之前的结果不同(除非您有大量的业余时间......) - ))。
#!/usr/bin/perl -w
use strict;
use warnings;
use Graph::Directed qw( );
my @rules = (
[qw( A B C )],
[qw( B D E F )],
[qw( C H G )],
[qw( G H )],
);
print @rules;
my $graph = Graph::Directed->new();
for (@rules) {
my $parent = shift(@$_);
for my $child (@$_) {
$graph->add_edge($parent, $child);
}
}
$graph->is_dag()
or die("Graph has a cycle--unable to analyze\n");
$graph->is_weakly_connected()
or die "Graph is not weakly connected--unable to analyze\n";
print join ' ', $graph->topological_sort(); # for eks A C B D G H E F