Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何遍历二进制抽象语法树以生成带有最小正确括号的中缀符号_Algorithm_Binary Tree - Fatal编程技术网

Algorithm 如何遍历二进制抽象语法树以生成带有最小正确括号的中缀符号

Algorithm 如何遍历二进制抽象语法树以生成带有最小正确括号的中缀符号,algorithm,binary-tree,Algorithm,Binary Tree,我被传递了一个表示数学公式的二进制AST。每个内部节点都是一个运算符,叶节点是操作数。我需要遍历树并以中缀符号输出公式。通过使用递归算法(如下面所示的Print()方法)遍历树,这很容易做到。Print()方法的问题是,在转换为中缀时操作顺序丢失,因为没有生成括号 我编写了PrintWithParens()方法,该方法输出正确的中缀公式,但添加了额外的括号。您可以在我的main方法的四种情况中的三种情况下看到,当不需要括号时,它会添加括号 我一直绞尽脑汁想弄清楚PrintWithMinimalP

我被传递了一个表示数学公式的二进制AST。每个内部节点都是一个运算符,叶节点是操作数。我需要遍历树并以中缀符号输出公式。通过使用递归算法(如下面所示的
Print()
方法)遍历树,这很容易做到。
Print()
方法的问题是,在转换为中缀时操作顺序丢失,因为没有生成括号

我编写了
PrintWithParens()
方法,该方法输出正确的中缀公式,但添加了额外的括号。您可以在我的main方法的四种情况中的三种情况下看到,当不需要括号时,它会添加括号

我一直绞尽脑汁想弄清楚
PrintWithMinimalParens()
的正确算法应该是什么。我确信一定有一种算法,在需要对术语进行分组时只能输出括号,但我一直无法正确实现它。我想我必须查看当前节点下树中运算符的优先级,但我现在使用的算法不起作用(请参见我的主要方法中的最后两种情况。不需要括号,但我的逻辑添加了括号)


是否可以实现我想要的
printwithminimaparens()
?树中的顺序是隐式的,这一事实是否使我想做的事情变得不可能?

如果左子级或右子级具有较低的优先级运算符,即使其中一个是较高或相等的优先级运算符,则将整个表达式括在括号中

我认为你需要把你的布尔需求分为左右两个孩子的不同情况。类似这样(未经测试):


在代码中,您将每个运算符与其子运算符进行比较,以查看是否需要在其周围加括号。但实际上,您应该将其与其父级进行比较。以下是一些可以确定是否可以省略括号的规则:

  • 在AST的根操作符周围不需要括号
  • 如果运算符A是运算符B的子级,且A的优先级高于B,则可以省略A周围的括号
  • 如果左关联运算符a是具有相同优先级的左关联运算符B的左子级,则可以省略a周围的括号。左关联运算符是将
    xay A z
    解析为
    (xay)A z
    的运算符
  • 如果右关联运算符a是具有相同优先级的右关联运算符B的右子级,则可以省略a周围的括号。右关联运算符是将
    xayaz
    解析为
    xa(yaz)
    的运算符
  • 如果您可以假设运算符A是,即
    (xay)Az=xa(yaz)
    对于所有x、y、z和A都是同一运算符A的子级,那么您可以选择省略子级A周围的括号。在这种情况下,重新对表达式进行分析将产生一个不同的AST,该AST在求值时给出相同的结果

  • 请注意,对于第一个示例,仅当您可以假设
    +
    是关联的(在处理普通数字时为真)并实现规则#5时,所需结果才是正确的。这是因为您的输入树是以右关联方式构建的,而操作符
    +
    通常是左关联的。

    在谷歌搜索[postfix to infix converter]时,在Ruby、C#、C、Java等语言中找到了很多很好的结果。这假设也可以,但我不知道它是否总是正确的(包括此的右关联变体):如果左关联运算符A是具有相同优先级的左关联运算符B的右子级,且B是关联的,则可以省略A周围的括号。
    public class Test {
    
    static abstract class Node {
    
        Node left;
        Node right;
        String text;
    
        abstract void Print();
        abstract void PrintWithParens();
        abstract void PrintWithMinimalParens();
    
        int precedence()
        {
            return 0;
        }
    }
    
    enum Operator { 
        PLUS(1,"+"), 
        MINUS(1, "-"), 
        MULTIPLY(2, "*"), 
        DIVIDE(2, "/"), 
        POW(3, "^") 
        ;
    
        private final int precedence;
        private final String text;
    
        private Operator(int precedence, String text)
        {
            this.precedence = precedence;
            this.text = text;
        }
    
        @Override
        public String toString() {
            return text;
        }
    
        public int getPrecedence() {
            return precedence;
        }
    }
    
    static class OperatorNode extends Node {
    
        private final Operator op;
    
        OperatorNode(Operator op)
        {
            this.op = op;
        }
    
        @Override
        void Print() {
            left.Print();
            System.out.print(op);
            right.Print();
        }
    
        @Override
        void PrintWithParens() {
            System.out.print("(");
            left.PrintWithParens();
            System.out.print(op);
            right.PrintWithParens();
            System.out.print(")");
        }
    
        @Override
        void PrintWithMinimalParens() {
    
            boolean needParens = 
                    (left.precedence() != 0 && left.precedence() < this.op.precedence) 
                    || 
                    (right.precedence() != 0 && right.precedence() < this.op.precedence);
    
            if(needParens)
                System.out.print("(");
    
            left.PrintWithMinimalParens();
            System.out.print(op);
            right.PrintWithMinimalParens();
    
            if(needParens)
                System.out.print(")");
    
        }
    
        @Override
        int precedence() {
            return op.getPrecedence();
        }
    
    }
    
    static class TextNode extends Node {
    
        TextNode(String text)
        {
            this.text = text;
        }
    
        @Override
        void Print() {
            System.out.print(text);
        }
    
        @Override
        void PrintWithParens() {
            System.out.print(text);
        }
    
        @Override
        void PrintWithMinimalParens() {
            System.out.print(text);
        }
    
    }
    
    private static void printExpressions(Node rootNode) {
    
        System.out.print("Print() : ");
        rootNode.Print();
        System.out.println();
        System.out.print("PrintWithParens() : ");
        rootNode.PrintWithParens();
        System.out.println();
        System.out.print("PrintWithMinimalParens() : ");
        rootNode.PrintWithMinimalParens();
        System.out.println();
        System.out.println();
    
    }
    
    public static void main(String[] args) 
    {
        System.out.println("Desired:  1+2+3+4");
        Node rootNode = new OperatorNode(Operator.PLUS);
        rootNode.left = new TextNode("1");
        rootNode.right = new OperatorNode(Operator.PLUS);
        rootNode.right.left = new TextNode("2");
        rootNode.right.right = new OperatorNode(Operator.PLUS);
        rootNode.right.right.left = new TextNode("3");
        rootNode.right.right.right = new TextNode("4");
    
        printExpressions(rootNode);
    
        System.out.println("Desired: 1+2*3+4");
        rootNode = new OperatorNode(Operator.PLUS);
        rootNode.left = new TextNode("1");
        rootNode.right = new OperatorNode(Operator.PLUS);
        rootNode.right.left = new OperatorNode(Operator.MULTIPLY);
        rootNode.right.left.left = new TextNode("2");
        rootNode.right.left.right = new TextNode("3");
        rootNode.right.right = new TextNode("4");
    
        printExpressions(rootNode);
    
        System.out.println("Desired: 1+2*(3+4)");
        rootNode = new OperatorNode(Operator.PLUS);
        rootNode.left = new TextNode("1");
        rootNode.right = new OperatorNode(Operator.MULTIPLY);
        rootNode.right.left = new TextNode("2");
        rootNode.right.right = new OperatorNode(Operator.PLUS);
        rootNode.right.right.left = new TextNode("3");
        rootNode.right.right.right = new TextNode("4");
    
        printExpressions(rootNode);
    
        System.out.println("Desired: 1+2^8*3+4");
        rootNode = new OperatorNode(Operator.PLUS);
        rootNode.left = new TextNode("1");
        rootNode.right = new OperatorNode(Operator.MULTIPLY);
        rootNode.right.left = new OperatorNode(Operator.POW);
        rootNode.right.left.left = new TextNode("2");
        rootNode.right.left.right = new TextNode("8");
        rootNode.right.right = new OperatorNode(Operator.PLUS);
        rootNode.right.right.left = new TextNode("3");
        rootNode.right.right.right = new TextNode("4");
    
        printExpressions(rootNode);
        }
    }
    
    Desired:  1+2+3+4
    Print() : 1+2+3+4
    PrintWithParens() : (1+(2+(3+4)))
    PrintWithMinimalParens() : 1+2+3+4
    
    Desired: 1+2*3+4
    Print() : 1+2*3+4
    PrintWithParens() : (1+((2*3)+4))
    PrintWithMinimalParens() : 1+2*3+4
    
    Desired: 1+2*(3+4)
    Print() : 1+2*3+4
    PrintWithParens() : (1+(2*(3+4)))
    PrintWithMinimalParens() : 1+(2*3+4)
    
    Desired: 1+2^8*3+4
    Print() : 1+2^8*3+4
    PrintWithParens() : (1+((2^8)*(3+4)))
    PrintWithMinimalParens() : 1+(2^8*3+4)
    
    void PrintWithMinimalParens() {
    
        boolean needLeftChildParens = 
                (left.precedence() != 0 && left.precedence() < this.op.precedence);
        boolean needRightChildParens = 
                (right.precedence() != 0 && right.precedence() < this.op.precedence);
    
        if(needLeftChildParens)
            System.out.print("(");
        left.PrintWithMinimalParens();
        if(needLeftChildParens)
            System.out.print(")");
    
        System.out.print(op);
    
        if(needRightChildParens)
            System.out.print("(");
        right.PrintWithMinimalParens();
        if(needRightChildParens)
            System.out.print(")");
    
    }
    
    1+2^8*(3+4)