中缀到后缀(反向波兰表示法)的转换工作与括号,但不能没有

本文关键字:工作 转换 但不能 后缀 表示 中缀 | 更新日期: 2023-09-27 18:16:09

分配规则:

  • 必须有单独的Operator类和单独的PostFix类包含转换方法。
  • 从左到右求值
  • 操作符被放置到Stack中。
  • 仅限二进制操作符
  • 分离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;
    }   

提前感谢!

中缀到后缀(反向波兰表示法)的转换工作与括号,但不能没有

好的,我得到了一些赞,表明有人对这个答案感兴趣。我的解决办法是再次扔掉我拥有的东西,重新开始。我坐下来,在纸上多次检查算法,然后一次调试一行。这导致了一些"有趣"的调整,只是为了完成这一点。

老实说,我想到的东西很恶心——在某一点上,我有一个for-else if-if-if-while-if。所以这个东西不好看,而且可能效率很低。幸运的是,我在这门课上没有效率评分,哈哈。我只是需要完成它,因为周五就要交了,而且我还有一个组装项目要开始。无论如何……

代码

操作符类在构造函数中更新了优先级值。

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)

Structure与Convert方法类似。有很多if(Stack.Count>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