为什么我需要明确引用 属性 才能修改它而不是使用引用?
Why am I required to explicitly refer to a property in order to modify it instead of using a reference?
我是 Perl 的新手。我第一次看到它是几天前,并决定练习实现一些算法和数据结构来学习。本例中为二叉搜索树 (BST)。
目前我正在使用一个 Node 包“Node.pm”,一个 BinarySearchTree 包“BST.pm”,以及一个使用代码“Main.pl”的入口点。
我的问题出现在使用对根 属性 的引用时插入树的根节点时(我知道它只是一个键 => 来自散列 table 的值,但是使用传统的 OOP术语我喜欢将其称为 属性)。
这是上下文的构造函数:
BST.pm
sub new() {
my $type = shift;
my $this = {};
my $list = shift;
$this->{'unordered_list'} = $list;
$this->{'root'} = undef;
bless($this, $type);
return $this;
}
构造函数采用整数列表来构造二叉搜索树,并且根节点在第一次调用“插入”之前是未定义的。
在对“BuildUnbalancedTree”的调用中,我传递了对 'root' 属性:
的引用
Main.pl
$bst = BST->new($nums);
$bst->BuildUnbalancedTree($bst->{'root'});
$bst->TraverseInOrder($bst->{'root'});
BST.pm
sub BuildUnbalancedTree(){
my $this = shift;
my $root = shift;
foreach my $key (@{$this->{'unordered_list'}}){
my $newnode = $this->NewNode($key);
$this->Insert($$root, $newnode);
}
}
在“插入”方法中,如果我尝试使用传递给它的变量插入根节点,除了根节点之外,树被部分构建。子节点都设置好了,但是根节点本身的值永远不会设置。
这是我希望有效但无效的方法:
sub Insert(){
my $this = shift;
my $root = shift;
my $node = shift;
if(!$root) {
$root = $node;
} elsif($node->{'value'} > $root->{'value'}) {
if(!$root->{'right'}) {
$root->{'right'} = $node;
} else {
$this->Insert($root->{'right'}, $node);
}
} else {
if(!$root->{'left'}){
$root->{'left'} = $node;
} else {
$this->Insert($root->{'left'}, $node)
}
}
}
假设第一个条件只会在第一次调用“插入”时为真,我更改了这一行:
$root = $node;
至:
$this->{'root'} = $node;
它确实有效,但我真的很想知道为什么另一种方法会出现问题。我相信这是因为我在对“BuildUnbalancedTree”的调用中取消引用了 root 参数(如果我不这样做,它会破坏一切)但真的很感谢确认和一些简短的专家分析。
您的方法 Insert
应该引用根而不是它的值。通过执行 $this->Insert($root, $newnode);
而不是 $this->Insert($$root, $newnode);
来调用它,并将 $root
的每个出现更改为 Insert
中的 $$root
,并将递归调用替换为 $this->Insert($$root->{'right'}, $node);
(left
也是一样)。
问题是,当您执行 $this->Insert($$root, $newnode);
时,您将根的 值 传递给了 Insert
。在第一次调用时,$root
尚未定义,这意味着您将 undef
传递给 Insert
(它存储在其本地值 $root
中)。因此,执行 if (!$root) { $root = node; }
只会在本地设置 $root
的值。
请注意,一旦将对根的引用传递给 Insert
(而不是值),就可以简化 Insert
方法:
sub Insert {
my ($root, $node) = @_;
if(!$$root) {
$$root = $node;
} elsif($node->{'value'} > $$root->{'value'}) {
Insert($$root->{'right'}, $node);
} else {
Insert($$root->{'left'}, $node);
}
}
我从参数中删除了 $this
,因为您从未使用过它。用 Insert($root, $newnode);
(而不是 $this->Insert(...)
)调用此 Insert
。
补充意见:
做 my $list = shift;
可能不是一个好主意:例如,如果你这样做:
my @list = (12, 5, 6, 19);
my $bst = BST->new(\@list);
push @list, 42;
$bst->BuildUnbalancedTree($bst->{'root'});
您的 BST 现在包含 42
,可能是 counter-intuitive。更好的方法可能是将列表(而不是数组引用)传递给构造函数:
sub new {
my $class = shift;
my @content = @_;
my $this = { unordered_list => \@content };
return bless($this, $class);
}
(请注意,我已经删除了 $this->{'root'} = undef;
:当您尝试访问它时,Perl 的自动生成会自动创建它)。
您的 BuildUnbalancedTree
方法将根作为参数,这有点令人惊讶,因为根存储在树中。我建议改为:
sub BuildUnbalancedTree {
my $this = shift;
foreach my $key (@{$this->{'unordered_list'}}){
my $newnode = $this->NewNode($key);
$this->Insert($this->{root}, $newnode);
}
}
我是 Perl 的新手。我第一次看到它是几天前,并决定练习实现一些算法和数据结构来学习。本例中为二叉搜索树 (BST)。
目前我正在使用一个 Node 包“Node.pm”,一个 BinarySearchTree 包“BST.pm”,以及一个使用代码“Main.pl”的入口点。
我的问题出现在使用对根 属性 的引用时插入树的根节点时(我知道它只是一个键 => 来自散列 table 的值,但是使用传统的 OOP术语我喜欢将其称为 属性)。
这是上下文的构造函数:
BST.pm
sub new() {
my $type = shift;
my $this = {};
my $list = shift;
$this->{'unordered_list'} = $list;
$this->{'root'} = undef;
bless($this, $type);
return $this;
}
构造函数采用整数列表来构造二叉搜索树,并且根节点在第一次调用“插入”之前是未定义的。
在对“BuildUnbalancedTree”的调用中,我传递了对 'root' 属性:
的引用Main.pl
$bst = BST->new($nums);
$bst->BuildUnbalancedTree($bst->{'root'});
$bst->TraverseInOrder($bst->{'root'});
BST.pm
sub BuildUnbalancedTree(){
my $this = shift;
my $root = shift;
foreach my $key (@{$this->{'unordered_list'}}){
my $newnode = $this->NewNode($key);
$this->Insert($$root, $newnode);
}
}
在“插入”方法中,如果我尝试使用传递给它的变量插入根节点,除了根节点之外,树被部分构建。子节点都设置好了,但是根节点本身的值永远不会设置。
这是我希望有效但无效的方法:
sub Insert(){
my $this = shift;
my $root = shift;
my $node = shift;
if(!$root) {
$root = $node;
} elsif($node->{'value'} > $root->{'value'}) {
if(!$root->{'right'}) {
$root->{'right'} = $node;
} else {
$this->Insert($root->{'right'}, $node);
}
} else {
if(!$root->{'left'}){
$root->{'left'} = $node;
} else {
$this->Insert($root->{'left'}, $node)
}
}
}
假设第一个条件只会在第一次调用“插入”时为真,我更改了这一行:
$root = $node;
至:
$this->{'root'} = $node;
它确实有效,但我真的很想知道为什么另一种方法会出现问题。我相信这是因为我在对“BuildUnbalancedTree”的调用中取消引用了 root 参数(如果我不这样做,它会破坏一切)但真的很感谢确认和一些简短的专家分析。
您的方法 Insert
应该引用根而不是它的值。通过执行 $this->Insert($root, $newnode);
而不是 $this->Insert($$root, $newnode);
来调用它,并将 $root
的每个出现更改为 Insert
中的 $$root
,并将递归调用替换为 $this->Insert($$root->{'right'}, $node);
(left
也是一样)。
问题是,当您执行 $this->Insert($$root, $newnode);
时,您将根的 值 传递给了 Insert
。在第一次调用时,$root
尚未定义,这意味着您将 undef
传递给 Insert
(它存储在其本地值 $root
中)。因此,执行 if (!$root) { $root = node; }
只会在本地设置 $root
的值。
请注意,一旦将对根的引用传递给 Insert
(而不是值),就可以简化 Insert
方法:
sub Insert {
my ($root, $node) = @_;
if(!$$root) {
$$root = $node;
} elsif($node->{'value'} > $$root->{'value'}) {
Insert($$root->{'right'}, $node);
} else {
Insert($$root->{'left'}, $node);
}
}
我从参数中删除了 $this
,因为您从未使用过它。用 Insert($root, $newnode);
(而不是 $this->Insert(...)
)调用此 Insert
。
补充意见:
做
my $list = shift;
可能不是一个好主意:例如,如果你这样做:my @list = (12, 5, 6, 19); my $bst = BST->new(\@list); push @list, 42; $bst->BuildUnbalancedTree($bst->{'root'});
您的 BST 现在包含
42
,可能是 counter-intuitive。更好的方法可能是将列表(而不是数组引用)传递给构造函数:sub new { my $class = shift; my @content = @_; my $this = { unordered_list => \@content }; return bless($this, $class); }
(请注意,我已经删除了
$this->{'root'} = undef;
:当您尝试访问它时,Perl 的自动生成会自动创建它)。您的
BuildUnbalancedTree
方法将根作为参数,这有点令人惊讶,因为根存储在树中。我建议改为:sub BuildUnbalancedTree { my $this = shift; foreach my $key (@{$this->{'unordered_list'}}){ my $newnode = $this->NewNode($key); $this->Insert($this->{root}, $newnode); } }