用Perl封装递归函数
我有一个代码在这里运行良好:用Perl封装递归函数,perl,function,subroutine,Perl,Function,Subroutine,我有一个代码在这里运行良好: #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %graph =( F => ['B','C','E'], A => ['B','C'], D => ['B'], C => ['A','E','F'], E => ['C
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %graph =(
F => ['B','C','E'],
A => ['B','C'],
D => ['B'],
C => ['A','E','F'],
E => ['C','F'],
B => ['A','E','F']
);
sub findPaths {
my( $seen, $start, $end ) = @_;
return [[$end]] if $start eq $end;
$seen->{ $start } = 1;
my @paths;
for my $node ( @{ $graph{ $start } } ) {
my %seen = %{$seen};
next if exists $seen{ $node };
push @paths, [ $start, @$_ ] for @{ findPaths( \%seen, $node, $end ) };
}
return \@paths;
}
my $start = "B";
my $end = "E";
print "@$_\n" for @{ findPaths( {}, $start, $end ) };
我想做的是生成一个更通用的子程序
所以它只需要\%graph、$start、$end作为输入并返回最终数组
我试图这样做,但它无法编译
sub findPathsAll {
my ($graph,$start,$end) = @_;
my $findPaths_sub;
$findPaths_sub {
my( $seen) = @_;
return [[$end]] if $start eq $end;
$seen->{ $start } = 1;
my @paths;
for my $node ( @{ $graph{ $start } } ) {
my %seen = %{$seen};
next if exists $seen{ $node };
push @paths, [ $start, @$_ ] for @{ &$findPaths_sub( \%seen, $node, $end ) };
}
return \@paths;
}
my @all;
push @all,@$_ for @{ &$findPaths_sub( {}, $start, $end ) };
return @all;
}
正确的方法是什么?我不知道您希望findPathsAll返回什么,所以这可能不是您想要的。无论如何,这里有一个FindPath到词汇递归coderef的翻译:
use Scalar::Util 'weaken';
sub findPathsAll {
my ($graph,$start,$end) = @_;
my $findPaths_sub;
my $strongRef = $findPaths_sub = sub {
my( $seen, $start, $end ) = @_;
return [[$end]] if $start eq $end;
$seen->{ $start } = 1;
my @paths;
for my $node ( @{ $graph->{ $start } } ) {
my %seen = %{$seen};
next if exists $seen{ $node };
push @paths, [ $start, @$_ ]
for @{ $findPaths_sub->( \%seen, $node, $end ) };
}
return \@paths;
};
weaken($findPaths_sub); # Prevent memory leak
my @all;
push @all,@$_ for @{ $findPaths_sub->( {}, $start, $end ) };
return @all;
## The above turns all the paths into one big list of nodes.
## I think maybe you meant this:
# return @{ $findPaths_sub->( {}, $start, $end ) };
## which would return a list of arrayrefs, one for each path.
}
一些注意事项:
您可以这样声明coderef:
$var = sub { ... };
$var->(arg1, arg2, ...);
请注意赋值运算符和尾随分号。如果希望coderef是递归的,则必须已声明$var。如果您说my$var=sub{…};,新变量在创建子变量之后才存在,因此它不能引用$var
你这样称呼它:
$var = sub { ... };
$var->(arg1, arg2, ...);
还有其他的语法,但我认为这是首选的
在我发布的第一个版本中有一个细微的内存泄漏。Perl使用引用计数垃圾收集器,这意味着它不能删除自引用数据结构。由于$findPaths_sub中的coderef捕获了对自身的引用,因此在程序退出之前,它永远不会被清除。我现在使用singingfish中提到的方法来避免这种情况$strongRef仅用于防止coderef在处理完之前被垃圾收集。我无法确定您希望findPathsAll返回什么,因此这可能不是您想要的。无论如何,这里有一个FindPath到词汇递归coderef的翻译:
use Scalar::Util 'weaken';
sub findPathsAll {
my ($graph,$start,$end) = @_;
my $findPaths_sub;
my $strongRef = $findPaths_sub = sub {
my( $seen, $start, $end ) = @_;
return [[$end]] if $start eq $end;
$seen->{ $start } = 1;
my @paths;
for my $node ( @{ $graph->{ $start } } ) {
my %seen = %{$seen};
next if exists $seen{ $node };
push @paths, [ $start, @$_ ]
for @{ $findPaths_sub->( \%seen, $node, $end ) };
}
return \@paths;
};
weaken($findPaths_sub); # Prevent memory leak
my @all;
push @all,@$_ for @{ $findPaths_sub->( {}, $start, $end ) };
return @all;
## The above turns all the paths into one big list of nodes.
## I think maybe you meant this:
# return @{ $findPaths_sub->( {}, $start, $end ) };
## which would return a list of arrayrefs, one for each path.
}
一些注意事项:
您可以这样声明coderef:
$var = sub { ... };
$var->(arg1, arg2, ...);
请注意赋值运算符和尾随分号。如果希望coderef是递归的,则必须已声明$var。如果您说my$var=sub{…};,新变量在创建子变量之后才存在,因此它不能引用$var
你这样称呼它:
$var = sub { ... };
$var->(arg1, arg2, ...);
还有其他的语法,但我认为这是首选的
在我发布的第一个版本中有一个细微的内存泄漏。Perl使用引用计数垃圾收集器,这意味着它不能删除自引用数据结构。由于$findPaths_sub中的coderef捕获了对自身的引用,因此在程序退出之前,它永远不会被清除。我现在使用singingfish中提到的方法来避免这种情况$strongRef仅用于防止coderef在我们完成之前被垃圾收集。I前几天。I前几天