【问题标题】:How to pass a tree data structure by reference in Perl?如何在 Perl 中通过引用传递树数据结构?
【发布时间】:2021-01-23 15:22:11
【问题描述】:

我正在编写一个脚本来解决非常基本的方程组。我将方程转换为二叉表达式树,隔离我想要的值的变量,然后进行替换。

这是我遇到问题的地方,我有一个函数“替换”,它遍历我想要替换的等式左侧的二进制表达式树。当我找到要替换的变量时,我将节点替换为另一个方程的表达式树。

但是当我尝试归还新树时,我的替代品不存在。 这显然是一个传递引用/传递值的问题,但我找不到解决它的方法。

这是一个显示不起作用的部分的脚本:

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

sub inorder {
    my $expression = shift;
    my $node = $expression;
    if ($node->{type} eq "operator") {
        print "(";
        inorder($node->{left});
        print $node->{value};
        inorder($node->{right});
        print ")";
    }
    else {
        print $node->{value};
    }
}

sub substitution {
    my ($inserted_equation, $master_equation) = @_;
    my $inserted_expression = $inserted_equation->{right_side};
    my $insertion_point     = $inserted_equation->{left_side}->{value};
    my $master_expression   = $master_equation->{right_side};

    my @stack_tree_walk;
    my $node = $master_expression;
    push @stack_tree_walk, {$node->%*, left_visited => 0, side=> "left"};

    while(@stack_tree_walk) {
        if ($node->{type} eq "variable" and $node->{value} eq $insertion_point) {
            foreach (@stack_tree_walk) {
                
            }

#           print $node->{value};
#           print Dumper $inserted_expression;
            $node = $inserted_expression;       # WORKS
#           print Dumper $node;                 # WORKS
#           print Dumper $master_expression;    # DOES NOT WORK
            pop @stack_tree_walk;
            $node = $stack_tree_walk[-1];
        }
        elsif ($node->{type} eq "operator") {
            if (not $stack_tree_walk[-1]->{left_visited}) {
                $stack_tree_walk[-1]->{left_visited} = 1;
                $node = $node->{left};
                push @stack_tree_walk, {$node->%*, left_visited => 0, side=> "left"};
            }
            elsif ($node->{side} eq "left") {
                $node = $node->{right};
                $stack_tree_walk[-1]->{side} = "right";
                push @stack_tree_walk, {$node->%*, left_visited => 0, side=> "left"};
            }
            else {
                pop @stack_tree_walk;
                $node = $stack_tree_walk[-1];
            }
        }
        else {
            pop @stack_tree_walk;
            $node = $stack_tree_walk[-1];
        }
    }
    return {right_side=>$master_expression, left_side=>$master_equation->{left_side}};
}


my $equation = {left_side => { type=> "variable",
                            value=> "y"},

                right_side=> { type=> "operator",
                            value=> "*",
                            left=> {type=> "variable", value=> "a"},
                            right=> {type=> "variable", value=> "b"} }

                };

my $insertion = {left_side => { type=> "variable" ,
                            value=> "a" },

                right_side=> { type=> "operator",
                            value=> "+",
                            left=> {type=> "variable", value=> "x"},
                            right=> {type=> "variable", value=> "y"} }
                };
$,="";
$\="";
print "equations before substitution\n";
inorder($equation->{left_side});
print "=";
inorder($equation->{right_side});
print "\n";
inorder($insertion->{left_side});
print "=";
inorder($insertion->{right_side});
print "\n";
print "------------------\n";

$,="\n";
$\="\n\n";
my $final = substitution($insertion, $equation);

$,="";
$\="";
print "------------------\n";
print "equation substituted\n";
inorder($final->{left_side});
print "=";
inorder($final->{right_side});
print "\n";

这是输出:

    equations before substitution
    y=(a*b)
    a=(x+y)

    equation substituted
    y=(a*b)                     <==== this is the ERROR
    y=((x+y)*b)                 <==== this should be the RIGHT result

我希望有人能告诉我哪一部分是错的。 谢谢。

【问题讨论】:

    标签: perl binary-tree pass-by-reference


    【解决方案1】:

    $node 本质上是一个指向结构的指针。您的代码只是将$node 设置为不同的指针,即$inserted_expression。您不会以这种方式更改结构,您只需更改局部变量 $node 以指向不同的事物。基本上你这样做:

      $struct = { foo => { bar => 1 } };
      $node = $struct->{foo}; # points at { bar => 1 } in $struct
      $node = { bar => 2 }  # points at { bar => 2 } and not longer into $struct
      print(Dumper($struct)); # unchanged
    

    如果您想更改结构中的值,您需要引用该值,而不仅仅是获取该值,即

      $struct = { foo => { bar => 1 } };
      $node = \$struct->{foo}; # reference to value of { foo => ... }, currently { bar => 1 }
      $$node = { bar => 2 }  # changes value of { foo => ... } to { bar => 2 }
      print(Dumper($struct)); # changed
    

    【讨论】:

    • 感谢您的回复!我刚刚将 $node = $inserted_expression 更改为 %$node = $inserted_expression->%* 并且它工作得很好。现在不需要返回值了。
    • 您可以在此处查看 Steffen Ullrich 的解决方案:Create a multidimesional key of hash from array
    猜你喜欢
    • 2011-08-06
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 2013-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多