背景:
我尝试实现Shunting-Yard 算法的一个变体,但不是将表达式输出为逆波兰表示法(RPN),而是在推入标记时更新自身,以便可以实时显示结果(就像您在计算器上按按钮并需要在每次操作后更新显示一样)。
这是 Shunting-Yard 类...
public class ShuntingYard
{
private Stack<double> _operands;
private Stack<Operation> _operations;
public ShuntingYard()
{
this._operands = new Stack<double>();
this._operations = new Stack<double>();
}
}
而Operation
类可能会是这样的...
public abstract class Operation
{
public abstract void Evaluate(Stack<double> operands, Stack<Operation> operations);
}
Evaluate()
函数会相应地更新堆栈,而“当前值”将是 _operands.Peek()
这里是我目前拥有的一些“操作”:
public class NullaryOperation : Operation { }
例如 Pi、e 等
只是将常数推入 _operands
public class UnaryOperation : Operation { }
例如平方根、正弦、余弦等
从 _operands
弹出一个数字,求值,并将结果推送到 _operands
public class BinaryOperation : Operation { }
例如 +、-、*、/ 等
检查优先级,如有需要则求值,并将结果推送到 _operands
这里是问题:
我需要能够将开括号
(
和闭括号)
推入算法的_operations
栈中。此外,当我添加一个闭括号时,我需要一直弹出操作数/运算符,直到遇到一个开括号。
我想要避免像这样的检查(检查对象类型):
while (operations.Peek().GetType() != typeof(OpenParen)) { ... }
我不想在Operation
中添加这样的方法:
public abstract bool IsOpenParen();
我可以做类似于这样的事情...
public abstract class Operation
{
public enum OperationType { Nullary, Unary, Binary, OpenParen, CloseParen };
public abstract OperationType GetOperationType() { };
public abstract void Evaluate(Stack<double> operands, Stack<Operation> operations);
}
但是要求所有子类型都将它们的类型指定为枚举似乎是一个糟糕的设计。
我应该如何建立模型以便在括号被推入时跟踪和处理它们?
另外,将括号视为“操作”似乎对我来说没有多大意义。然而,维基百科上的算法是这样处理它们的,我想不出其他方法来跟踪它们相对于其他“真实”操作的位置。
谢谢。
ShuntingYard
对象。当你遇到右括号时,你可以完成解析该序列并返回到之前的序列。 - StarPilot