Algorithm 如何遍历二进制抽象语法树以生成带有最小正确括号的中缀符号
我被传递了一个表示数学公式的二进制AST。每个内部节点都是一个运算符,叶节点是操作数。我需要遍历树并以中缀符号输出公式。通过使用递归算法(如下面所示的Algorithm 如何遍历二进制抽象语法树以生成带有最小正确括号的中缀符号,algorithm,binary-tree,Algorithm,Binary Tree,我被传递了一个表示数学公式的二进制AST。每个内部节点都是一个运算符,叶节点是操作数。我需要遍历树并以中缀符号输出公式。通过使用递归算法(如下面所示的Print()方法)遍历树,这很容易做到。Print()方法的问题是,在转换为中缀时操作顺序丢失,因为没有生成括号 我编写了PrintWithParens()方法,该方法输出正确的中缀公式,但添加了额外的括号。您可以在我的main方法的四种情况中的三种情况下看到,当不需要括号时,它会添加括号 我一直绞尽脑汁想弄清楚PrintWithMinimalP
Print()
方法)遍历树,这很容易做到。Print()
方法的问题是,在转换为中缀时操作顺序丢失,因为没有生成括号
我编写了PrintWithParens()
方法,该方法输出正确的中缀公式,但添加了额外的括号。您可以在我的main方法的四种情况中的三种情况下看到,当不需要括号时,它会添加括号
我一直绞尽脑汁想弄清楚PrintWithMinimalParens()
的正确算法应该是什么。我确信一定有一种算法,在需要对术语进行分组时只能输出括号,但我一直无法正确实现它。我想我必须查看当前节点下树中运算符的优先级,但我现在使用的算法不起作用(请参见我的主要方法中的最后两种情况。不需要括号,但我的逻辑添加了括号)
是否可以实现我想要的
printwithminimaparens()
?树中的顺序是隐式的,这一事实是否使我想做的事情变得不可能?如果左子级或右子级具有较低的优先级运算符,即使其中一个是较高或相等的优先级运算符,则将整个表达式括在括号中
我认为你需要把你的布尔需求分为左右两个孩子的不同情况。类似这样(未经测试):
在代码中,您将每个运算符与其子运算符进行比较,以查看是否需要在其周围加括号。但实际上,您应该将其与其父级进行比较。以下是一些可以确定是否可以省略括号的规则:
xay A z
解析为(xay)A z
的运算符xayaz
解析为xa(yaz)
的运算符(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)