【问题标题】:Infix to Postfix(Reverse Polish Notation) conversion works with parentheses but not without中缀到后缀(反向波兰表示法)转换使用括号但并非没有
【发布时间】:2016-11-03 23:01:49
【问题描述】:

分配规则:

  • 必须具有单独的 Operator 类和包含转换方法的单独 PostFix 类。
  • 从左到右评估。
  • 运算符被放入堆栈中。
  • 仅限二元运算符
  • 独立的 Operator 类和 PostFix 类,其中 PostFix 包含 Conversion 方法。
  • C#

我的问题:

如果所有/大部分等式都在括号中,则我的转换有效。仅当输入按操作顺序时,它才可以在没有括号的情况下工作。

我相信我只是没有正确检查优先级,但我不确定这是问题所在。我现在已经重写了我的转换方法 4 次,并且花了大约 25 小时在调试器中调整和运行该方法的不同迭代和谷歌搜索,但我只是不理解问题在我的代码中的位置。我在调试时看到了它,但我不确定我必须做些什么来修复它,所以我认为第三方的观点可能会有所帮助。

示例

输出不正确:

a=5+3/4-(9*8-1)*1         =>        a 5 3 + 4 / 9 8 * 1 -  - 1 * = 
      should be       a 5 3 4 / + 9 8 * 1 - - 1 * =

alpha = beta + gamma * delta        =>        alpha beta gamma + delta * = 
      should be       alpha beta gamma delta * + =

正确的输出:

a = ((((a+b)-c)*d)/(e+1))         =>        a a b +  c -  d *  e 1 +  /  = 

alpha = beta * gamma + delta         =>        beta gamma * delta + alpha =

我的代码

算子类:

class Operator
{
    private byte precedence = 1;        //Precedence of operator over others
    private char identity = 'x';        //the character behind the operator

    /// <summary>
    /// Creates an operator based on the passed character
    /// </summary>
    /// <param name="OperatorIn">Character definition of the operator</param>
    public Operator(char OperatorIn)
    {
        identity = OperatorIn;
        switch (OperatorIn)
        {
            case '*':
                precedence = 2;
                break;
            case '/':
                precedence = 2;
                break;
            case '(':
                precedence = 3;
                break;

            case ')':
                precedence = 3;
                break;

            case '=':
                precedence = 3;
                break;
            case '+':
                precedence = 1;
                break;

            case '-':
                precedence = 1;
                break;

            default:
                precedence = 0;
                break;
        }//switch
    }//Operator(char)

    /// <summary>
    /// Retrieves the char representation of the operator
    /// </summary>
    /// <returns>Char representation of the operator</returns>
    public char ToChar()
    {
        return this.identity;
    }//ToChar()

    /// <summary>
    /// Returns the byte value of precedence of the operator
    /// </summary>
    /// <returns>byte value of precedence</returns>
    public byte GetPrecedence()
    {
        return this.precedence;
    }
}//Operator

转换方式:

public static string Convert(string infix)
    {
        #region original
        Stack<Operator> OpStack = new Stack<Operator>();
        String Postfix = String.Empty;
        InfixPostfix.Operator Previous = new Operator('x'),
                              Current = null;   //NextOp = new Operator(infix[infix.IndexOfAny(Ops, i)]);
        char[] Ops = {'+','-','=','*','/'};
        string term = String.Empty;

        foreach(char c in infix)
        {
            if (Ops.Contains(c))                        //if the char is one of the operator chars
            {
                Postfix += term + " ";                  //split term and add to output
                while (OpStack.Count > 0)               //While there's actually operators in the stack  
                {
                    Current = OpStack.Pop();            //Assign the operator as Current Operator
                    if (Current.GetPrecedence() < Previous.GetPrecedence())     //If Current Op is less priority than preceding Op
                        Postfix += Current.ToChar() + " ";                      //Output the character of the Op
                    else                                //If Current Op priority is higher than the previous
                    {
                        Previous = Current;             //Store the current as previous to move on
                        OpStack.Push(Current);          //Store current in stack
                        break;                          //Move to next char
                    }//else
                }//while
                OpStack.Push(new Operator(c));          //If stack is empty, push the operator
                term = "";                              // and reset the term to empty
            }//if
            else if (c == ')')                          //If the char is a close paren
            {
                Postfix += term + " ";                  //store the previous characters as a term in postfix
                term = "";                              //establish a new term
                Previous = Current;                     //Set Current as the old Op
                Current = OpStack.Pop();                //Get the new Current op
                while (Current.ToChar() != '(')         //Pop the stack until you get an open paren op
                {
                    Postfix += Current.ToChar() + " ";  //Add the term to the output string
                    //Previous = Current;
                    try
                    {
                        Current = OpStack.Pop();        //Try to pop another operator
                    }//try
                    catch(Exception)                    //If the stack is empty
                    {
                        return "Error! Mismatched parentheses!";    //Then there is a missing/misaligned paren
                    }//catch
                }//while
            }//else if
            else if (c == '(')                          //If the op is an open paren
                OpStack.Push(new Operator(c));          //store it
            else if (c != ' ')                          //If it's an alphanumeric char, 
                term += c;                              //build a term with it
        }//foreach
        Postfix += term + " ";                          //add the last term to the output
        while(OpStack.Count > 0)                        //If there are remaining ops on the stack,
        {
            Current = OpStack.Pop();                    //pop them off
            if (Current.ToChar() == '(' || Current.ToChar() == ')') //If there is a paren remaining
                return "Error! Mismatched parentheses!";            // it's because of missing complement or misalignment
            Postfix += Current.ToChar() + " ";              //if regular op, add to output
        }//while
        return Postfix;
    }   

提前谢谢你!

【问题讨论】:

标签: c# postfix-notation infix-notation


【解决方案1】:

好的,所以,我得到了一些支持,表明有人对答案感兴趣。我的解决方案是再次丢弃我拥有的东西并重新开始。我坐下来,在纸上多次检查算法,然后一次调试一行。这导致了一些“有趣”的调整,只是为了完成这个。

老实说,我想出的东西令人作呕——有一次我有一个 for-else if-if-if-while-if。所以这个东西并不漂亮,而且可能真的效率低下。幸运的是我在这门课上没有得到效率评分,哈哈。我只需要完成它,因为它将于周五到期,我有一个装配项目要开始。总之……

代码

Operator 类在构造函数中更新了优先级值。

public Operator(char OperatorIn)
    {
        identity = OperatorIn;
        switch (OperatorIn)
        {
            case '*':
                precedence = 2;
                break;
            case '/':
                precedence = 2;
                break;

            case '=':
                precedence = 1;
                break;
            case '+':
                precedence = 1;
                break;

            case '-':
                precedence = 1;
                break;

            default:
                precedence = 0;
                break;
        }//switch
    }//Operator(char)

Convert 方法的结构类似。有很多 if(Stack.Count&gt;0) 检查可能表明循环和其他 if/while 内的逻辑错误。但它似乎工作得很好。

public static string Convert(string infix)
    {
        Stack<Operator> OpStack = new Stack<Operator>();
        String Postfix = String.Empty;
        Operator Previous = new Operator('x'),
                 Current = null;
        char[] Ops = { '+', '-', '=', '*', '/' };
        string term = String.Empty;

        foreach (char c in infix)                           //Iterate through char at a time
        {
            if (c == '(')                                   //If open paren
                OpStack.Push(new Operator(c));              // put on the stack
            else if (c == ')')                              //If close paren
            {
                Postfix += term + " ";                      //Output the term
                term = "";                                  // and clear out the term holder
                Previous = OpStack.Peek();                  //Get a value to know Previous has as real value instead of 'x'
                while (Previous.ToChar() != '(')             // pop until we reach the open paren
                {
                    if (OpStack.Count > 0)
                        Current = OpStack.Pop();                //Current becomes what was on top of the stack
                    if(Current.ToChar() != ')' && Current.ToChar() != '(')
                        Postfix += Current.ToChar() + " ";       //  add to output
                    try                                          //Make sure we have more to pop
                    {
                        Previous = OpStack.Pop();                //Previous becomes what was 2nd on the stack
                    }//try
                    catch (Exception)                            //If there's nothing to pop and we're still in this loop
                    {
                        return "Error! Mismatched parentheses!"; //Mismatched or missing parenthesis
                    }//catch
                }//while
            }//else if
            else if (Ops.Contains(c))                       //If it's an operator
            {
                Postfix += term + " ";                      //output the term
                term = "";                                  // and clear the term holder
                Current = new Operator(c);                  //Assign the current character as Current Op
                if (OpStack.Count > 0)                      //If there are previous ops in stack
                {
                    Previous = OpStack.Peek();              // get top op on stack to compare

                    if (Previous.GetPrecedence() > Current.GetPrecedence() && OpStack.Count > 0)            //Decide between > and =
                    {
                        while (Previous.GetPrecedence() > Current.GetPrecedence() && OpStack.Count > 0)       //Pop until we find lesser precedence op
                        {
                            Previous = OpStack.Pop();           //Remove the compared value from stack
                            Postfix += Previous.ToChar() + " "; //Add the popped ops to output
                            if (OpStack.Count > 0)              //make sure we aren't looping too far
                                Previous = OpStack.Peek();      //assign new value before compare occurs
                        }//while 
                    }//if
                    else if(Previous.GetPrecedence() == Current.GetPrecedence() && OpStack.Count > 0 && Previous.ToChar() != '=')       //Decide between > and =
                    {
                        while (Previous.GetPrecedence() == Current.GetPrecedence() && OpStack.Count > 0 && Previous.ToChar() != '=')    //Pop until = precedence found
                        {
                            Previous = OpStack.Pop();           //Remove the compared value from stack
                            Postfix += Previous.ToChar() + " "; //Add the popped ops to output
                            if (OpStack.Count > 0)              //make sure we aren't looping too far
                                Previous = OpStack.Peek();      //assign new value before compare occurs
                        }//while
                    }//else if
                    OpStack.Push(Current);                  //Once a <= op is found, store the Current op
                    continue;
                }//if
                else                                        //If there are no ops on stack
                    OpStack.Push(Current);                  // store it immediately
            }//else if
            else if (c != ' ')                              //If alphanumeric
                term += c;                                  // add into term holder
        }//foreach
        Postfix += term + " ";                              //There will be a term left over after the final c, so output it
        while(OpStack.Count > 0)                            //There may also be ops left, so pop them
        {
            Current = OpStack.Pop();
            if (Current.ToChar() == '(' || Current.ToChar() == ')') //If there is a paren remaining
                return "Error! Mismatched parentheses!";            // it's because of missing complement or misalignment
            Postfix += Current.ToChar() + " ";                      //output the operator
        }//while
        return Postfix;
        }//Convert v2

【讨论】:

    猜你喜欢
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-09
    • 2014-08-26
    相关资源
    最近更新 更多