中缀到Postfix和一元/二元运算符

我有一段代码将中缀表达式转换为内存中的表达式树。 这很好用。 只有一个小问题。 我只是想弄清楚如何正确地使用一元运算符(正确的关联运算符)。

使用以下中缀表达式:

+1 + +2 - -3 - -4 

我希望RPN为:

 1+2++3-4-- 

然而,我能找到的在线中缀后转换器都没有像我期望的那样处理这个例子。 有没有人对处理右关联运算符有明确的解释,特别是那些可以被误认为是一元运算符的二元运算符?

编辑/澄清:我想知道如何在从中缀到后缀的翻译过程中处理一元运算符。 即:识别相同的’ – ‘字符,例如作为一元而不是二元运算符,因此具有不同的优先级。 我会考虑使用状态机,或许有两个状态,但……?

那么,您需要在解析阶段确定给定的运算符是否为二进制/一元。 一旦这样做,当您创建RPN时,您可以将运算符标记为采用2或1个参数。

您可以尝试使用Shunting Yard算法进行解析(以及同时创建RPN),这也是为了与一元运算符一起工作。

在任何情况下,如果您关心的只是一元+或 – ,当您看到“意外”出现的+或 – 时,您只需插入带括号的0。

例如

+1 + +2 - -3 - -4

你应该能够通过它并转换为

(0+1) + (0+2) - (0-3) - (0-4)

现在你不需要担心一元+或 – 并且可能忘记用它们所采用的参数数量来标记运算符。

可能是这个混乱的C#代码会帮助你。 一元运算符在算术运算中具有最大优先级,因此它们的优先级将更高。 为了识别一元运算符我已经采用了一个布尔变量一元,它将在每个运算符标记后设置为true,在操作数之后设置为false。 您必须对一元加号和减号运算符使用不同的表示法,以便您可以区分PFE中的一元和二元运算符。 这里’#’和’〜’用于描述后缀表达式(PFE)中的一元加和一元减号。

你可以使用这个approch处理所有情况,如1 + -1,1 +( – 1),1 — 1,1 + – 1。

 using System; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DSA { class Calculator { string PFE; public Calculator() { Console.WriteLine("Intializing Calculator"); } public double Calculate(string expression) { ConvertToPost(expression); return CalculatePOST(); } public void ConvertToPost(string expression) { expression = "(" + expression + ")"; var temp = new DSA.Stack(); string ch = string.Empty; bool unary = true; char a; foreach (var b in expression) { a = b; if (!a.IsOperator()) { ch += a.ToString(); unary = false; } else { if (ch!=string.Empty) PFE += ch+","; ch = string.Empty; if(a!='(' && a!=')') { if (unary == true) { if (a == '-') a = '~'; else if (a == '+') a = '#'; else throw new InvalidOperationException("invalid input string"); } try { if (a.Precedence() <= temp.Peek().Precedence()) { PFE += temp.Pop().ToString() + ","; } } catch(InvalidOperationException e) { } temp.Push(a); unary = true; } if (a == '(') { temp.Push(a);} if(a==')') { for(char t=temp.Pop();t!='(';t=temp.Pop()) { PFE += t.ToString() + ","; } } } } } public double CalculatePOST() { var eval = new Stack(); string ch = string.Empty; bool skip = false; foreach(char c in PFE) { if(!c.IsOperator()) { if (c == ',') { if (skip == true) { skip = false; continue; } eval.Push(Double.Parse(ch)); ch = string.Empty; } else ch += c; } else { if (c == '~') { var op1 = eval.Pop(); eval.Push(-op1); } else if (c == '#') ; else { var op2 = eval.Pop(); var op1 = eval.Pop(); eval.Push(Calc(op1, op2, c)); } skip = true; } } return eval.Pop(); } private double Calc(double op1, double op2, char c) { switch(c) { case '+': return op1 + op2; case '-': return op1 - op2; case '*': return op1 * op2; case '%': return op1 % op2; case '/': return op1 / op2; case '^': return float.Parse(Math.Pow(op1,op2).ToString()); default: throw new InvalidOperationException(); } } } public static class extension { public static bool IsOperator(this char a) { char[] op = {'+','-','/','*','(',')','^','!','%','~','#'}; return op.Contains(a); } public static int Precedence(this char a) { if (a == '~' || a== '#') return 1; if (a == '^') return 0; if (a == '*' || a == '/' || a=='%') return -1; if (a == '+' || a == '-') return -2; return -3; } } }