Infix到Postfix(反向波兰表示法)转换适用于括号,但不是没有

时间:2016-11-03 23:01:49

标签: c# postfix-notation infix-notation

转让规则:

  • 必须具有单独的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;
    }   

提前谢谢!

1 个答案:

答案 0 :(得分:0)

好吧,所以,我得到了一些表示对答案感兴趣的赞成票。我的解决方案再次摧毁了我所拥有的并重新开始。我坐下来,多次在纸上完成算法,然后在调试一行的同时完成它。这导致一些“有趣”的调整只是为了完成这个。

老实说,我想出的是令人作呕的 - 有一点我有一个 - 如果 - 如果 - 如果 - 如果。所以这件事并不漂亮,而且效率可能非常低。幸运的是,我没有在这堂课上获得效率评分,哈哈。我只需要在星期五完成它,我就有一个装配项目。无论如何...

代码

运算符类已在构造函数中更新了优先级值。

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>0)检查可能表示循环内部和其他if / whiles中的逻辑错误。但它似乎完美无缺。

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