珀尔 |递归子程序
先决条件: Perl 中的递归
递归意味着属于或使用可以重复应用的规则或程序。它是通过重复应用算法来定义函数或计算数字的过程。递归子例程是一种子例程,它在执行过程中调用自身或处于潜在的函数调用循环中。 Perl 为我们提供了迭代和递归使用子程序的灵活性。
一个简单的例子展示了在 Perl 中递归子程序的使用,计算一个数字的阶乘。
例子 :
Perl
#!/usr/bin/perl
# Perl Program to calculate Factorial
sub factorial
{
my $n = $_[0];
# checking if that value is 0 or 1
if ($n == 0 || $n == 1)
{
return 1;
}
# Recursively calling the function with the next value
# which is one less than current one
else
{
return $n * factorial($n - 1);
}
}
# Driver Code
$n = 7;
# Function call and printing result after return
print "Factorial of a number $n is ", factorial($n);
Perl
#!/usr/bin/perl
use strict;
use warnings;
use File::Find::Rule;
use File::Basename qw(basename);
my $loc = "C:\Users\GeeksForGeeks";
my $file = 'final.txt';
my $expected = ;
chomp $expected;
open(my $fh, '<', $expected) or
die "Could not open '$expected' $!\n";
open(my $out, '>', $file) or
die "Could not open '$file' $!\n";
my @paths = File::Find::Rule->file->name('*.pdf')->in($loc);
my @files = map { lc basename $_ } @paths;
my %case = map { $_ => 1 } @files;
print $out "This file has been copied from ($loc)$file:\n";
while (my $name = <$fh>)
{
chomp $name;
if ($case{lc $name})
{
print "$name found\n";
}
else
{
print $out "$name\n";
}
}
close $out;
close $fh;
Perl
#!/usr/bin/perl
# Perl recursive Program to walk
# through a directory tree
use strict;
use warnings;
use 5.010;
my $loc = shift || '.';
# Calling walk subroutine with
# the location of the root directory
walk($loc);
# Subroutine definition
sub walk
{
my ($case) = @_;
# If case is not a directory itself
return if not -d $case;
# If case is a directory
opendir my $dh, $case or die;
while (my $sub = readdir $dh)
{
next if $sub eq '.' or $sub eq '..';
say "$case/$sub";
walk("$case/$sub");
}
close $dh;
return;
}
Perl
use strict;
use warnings;
use 5.010;
my $loc = shift || '.';
walk($loc);
sub walk
{
my ($case) = @_;
say $case;
return if not -d $case;
opendir my $dh, $case or die;
while (my $sub = readdir $dh)
{
next if $sub eq '.' or $sub eq '..';
walk("$case/$sub");
}
close $dh;
return;
}
Perl
#!/usr/bin/perl
# Perl Program to calculate Factorial
sub myfunc
{
my $n = $_[0];
# checking if that value is
# greater than 0 or not
if ($n <= 0)
{
print "Now, You are on GFG portal.\n";
}
# Recursively calling function with
# the next value which is one less
# than current one
else
{
print "$n\n";
myfunc($n - 1);
}
}
# Driver Code
# Function call
myfunc(3);
Factorial of a number 7 is 5040
遍历目录树
遍历目录树意味着迭代或打印根目录中的每个文件和子目录。目录树是以树的形式表示子目录和子目录中的文件以及目录中的其他文件,表示这些目录和各个文件之间的父子关系。
Unix和Windows系统都将文件目录组织成树形结构。虽然在 Perl 中,遍历目录树或遍历目录树既可以迭代也可以递归完成,但是当我们的根文件夹中的文件或子目录的数量非常大时,我们经常使用后者。这是因为与迭代函数相比,以递归函数编写的代码行数更快且代码行数更少。后者在相应的文件数量较少时使用。
我们将使用File::Find迭代地遍历文件系统并收集文件名。
Syntax :
use File::Find;
find(\&wanted, @directories_to_search);
sub wanted { … }
use File::Find;
finddepth(\&wanted, @directories_to_search);
sub wanted { … }
use File::Find;
find({ wanted => \&process, follow => 1 }, ‘.’);
例子 :
Perl
#!/usr/bin/perl
use strict;
use warnings;
use File::Find::Rule;
use File::Basename qw(basename);
my $loc = "C:\Users\GeeksForGeeks";
my $file = 'final.txt';
my $expected = ;
chomp $expected;
open(my $fh, '<', $expected) or
die "Could not open '$expected' $!\n";
open(my $out, '>', $file) or
die "Could not open '$file' $!\n";
my @paths = File::Find::Rule->file->name('*.pdf')->in($loc);
my @files = map { lc basename $_ } @paths;
my %case = map { $_ => 1 } @files;
print $out "This file has been copied from ($loc)$file:\n";
while (my $name = <$fh>)
{
chomp $name;
if ($case{lc $name})
{
print "$name found\n";
}
else
{
print $out "$name\n";
}
}
close $out;
close $fh;
输出:源文件被复制到目标文件
在接下来的部分中,我们将讨论根目录的递归遍历。
递归遍历目录树
遍历的迭代解决方案除了速度慢、代码行多外,问题在于根目录中的所有子目录必须具有相同的方向和相同数量的文件。否则,遍历可能成为一项复杂的任务。递归解决方案在克服迭代解决方案的问题方面发挥了更好的作用。
示例(递归):
Perl
#!/usr/bin/perl
# Perl recursive Program to walk
# through a directory tree
use strict;
use warnings;
use 5.010;
my $loc = shift || '.';
# Calling walk subroutine with
# the location of the root directory
walk($loc);
# Subroutine definition
sub walk
{
my ($case) = @_;
# If case is not a directory itself
return if not -d $case;
# If case is a directory
opendir my $dh, $case or die;
while (my $sub = readdir $dh)
{
next if $sub eq '.' or $sub eq '..';
say "$case/$sub";
walk("$case/$sub");
}
close $dh;
return;
}
输出 :
上面的代码将让您遍历根目录中的每个文件以及根目录中存在的所有子目录以及这些子目录中的文件和目录。
自上而下的方法
自上而下的方法基本上将一个复杂的问题或算法分成多个较小的部分(模块) 。这些模块被进一步划分,直到得到的模块是不能进一步分解的程序。
在这里,我们首先初始化一个名为 $case 的变量,它保存被迭代或循环的文件或目录。然后如果它是一个文件,那么该函数简单地打印它的名称并循环到下一个文件或目录,否则如果 $case 是一个目录,那么它再次调用子例程,将目录位置作为当前目录位置,然后循环该目录中的所有文件和子目录。内部函数完成后,指针返回到外部目录的位置并打印其名称,然后移动到下一个文件或根目录中存在的目录。这实际上是 Perl 中用于遍历或遍历目录树的典型自顶向下方法。
例子 :
Perl
use strict;
use warnings;
use 5.010;
my $loc = shift || '.';
walk($loc);
sub walk
{
my ($case) = @_;
say $case;
return if not -d $case;
opendir my $dh, $case or die;
while (my $sub = readdir $dh)
{
next if $sub eq '.' or $sub eq '..';
walk("$case/$sub");
}
close $dh;
return;
}
输出 :
递归遍历目录树一节中解释的代码是 Perl 中使用的自顶向下方法的一个示例。
Note : The above Output image shows a small portion of the complete output as there are a lot of files and subdirectories inside the root directory. This code works fine for folders and directories with a small number of sub-directories.
递归函数
递归函数具有以下一般形式:
Function( arguments ) {
if a simple case, return the simple value // base case / stopping condition
else call function with simpler version of problem
}
例子 :
Perl
#!/usr/bin/perl
# Perl Program to calculate Factorial
sub myfunc
{
my $n = $_[0];
# checking if that value is
# greater than 0 or not
if ($n <= 0)
{
print "Now, You are on GFG portal.\n";
}
# Recursively calling function with
# the next value which is one less
# than current one
else
{
print "$n\n";
myfunc($n - 1);
}
}
# Driver Code
# Function call
myfunc(3);
输出:
为了使递归函数停止调用自身,我们需要某种类型的停止条件。如果它不是基本情况,那么我们使用通用公式简化我们的计算。递归函数有两个主要部分。第一个检查某些条件并在满足该条件时返回。这称为停止条件或停止条件。然后在函数的某个稍后时刻,它使用一组与之前调用不同的参数来调用自己。
为什么递归优于迭代?
- 它具有编写更简洁的短代码的优点。
- 如果与记忆一起使用,它在时间方面也很有效
- 在解决基于树结构的问题时表现更好。