【问题标题】:Convert from an infix expression to postfix (C++) using Stacks使用堆栈从中缀表达式转换为后缀 (C++)
【发布时间】:2012-09-22 22:34:06
【问题描述】:

我的讲师给了我一个任务,让我创建一个程序来使用 Stacks 将表达式转换和中缀为后缀。我已经制作了堆栈类和一些函数来读取中缀表达式。

但是这个名为convertToPostfix(char * const inFix, char * const postFix) 的函数负责使用堆栈将数组inFix 中的inFix 表达式转换为数组postFix 中的后修复表达式,但它并没有做它应该做的事情。你们能帮帮我,告诉我我做错了什么吗?

以下是从 inFix 转换为 postFix 的函数的代码,convertToPostfix(char * const inFix, char * const postFix) 是我需要帮助修复的代码:

 void ArithmeticExpression::inputAndConvertToPostfix()
    {
       char inputChar; //declaring inputChar
       int i = 0; //inizalize i to 0

       cout << "Enter the Arithmetic Expression(No Spaces): ";

       while( ( inputChar = static_cast<char>( cin.get() ) ) != '\n' )
       {
          if (i >= MAXSIZE) break; //exits program if i is greater than or equal to 100

          if(isdigit(inputChar) || isOperator(inputChar))
          {
             inFix[i] = inputChar; //copies each char to inFix array
             cout << inFix[i] << endl;
          }
          else
             cout << "You entered an invalid Arithmetic Expression\n\n" ;

          }

          // increment i;
          i++;
          convertToPostfix(inFix, postFix);


       }




    bool ArithmeticExpression::isOperator(char currentChar)
    {

        if(currentChar == '+')
            return true;
        else if(currentChar == '-')
            return true;
        else if(currentChar == '*')
            return true;
        else if(currentChar == '/')
            return true;
        else if(currentChar == '^')
            return true;
        else if(currentChar == '%')
            return true;
        else
            return false;
    }

    bool ArithmeticExpression::precedence(char operator1, char operator2)
    {
        if ( operator1 == '^' )
           return true;
        else if ( operator2 == '^' )
           return false;
        else if ( operator1 == '*' || operator1 == '/' )
           return true;
        else if ( operator1 == '+' || operator1 == '-' )
           if ( operator2 == '*' || operator2 == '/' )
              return false;
           else
              return true;

        return false;
    }

   void ArithmeticExpression::convertToPostfix(char * const inFix, char * const postFix)
        {
           Stack2<char> stack;

           const char lp = '(';

           stack.push(lp); //Push a left parenthesis ‘(‘ onto the stack.

           strcat(inFix,")");//Appends a right parenthesis ‘)’ to the end of infix.

          // int i = 0;
           int j = 0;

           if(!stack.isEmpty())
           {

               for(int i = 0;i < 100;){

                   if(isdigit(inFix[i]))
                   {
                        postFix[j] = inFix[i];
                        cout << "This is Post Fix for the first If: " << postFix[j] << endl;
                        i++;
                        j++;
                   }

                    if(inFix[i] == '(')
                   {
                       stack.push(inFix[i]);
                       cout << "The InFix was a (" << endl;
                       i++;
                       //j++;
                   }

                    if(isOperator(inFix[i]))
                               {
                            char operator1 = inFix[i];

                            cout << "CUrrent inFix is a operator" << endl;
                                   if(isOperator(stack.getTopPtr()->getData()))
                                       {
                                       cout << "The stack top ptr is a operator1" << endl;
                                       char operator2 = stack.getTopPtr()->getData();
                                           if(precedence(operator1,operator2))
                                           {
                                               //if(isOperator(stack.getTopPtr()->getData())){
                                                   cout << "The stack top ptr is a operato2" << endl;
                                                   postFix[j] = stack.pop();
                                                   cout << "this is post fix " << postFix[j] << endl;
                                                   i++;
                                                   j++;
                                              // }

                                           }

                                       }
                                   else

                                       stack.push(inFix[i]);
                                   // cout << "Top Ptr is a: "<< stack.getTopPtr()->getData() << endl;



                               }

                    for(int r = 0;r != '\0';r++)
                        cout << postFix[r] << " ";

                        if(inFix[i] == ')')
                       {
                           while(stack.stackTop()!= '(')
                         {
                               postFix[j] = stack.pop();
                               i++;
                               j++;
                                }
                           stack.pop();

                            }
                       }
           }

                   }

请注意,函数 convertToPostfix 是使用此算法生成的:

  • 将左括号“(”压入堆栈。
  • 在中缀末尾添加右括号“)”。
  • 当堆栈不为空时,从左到右读取中缀并执行以下操作:

    • 如果中缀中的当前字符是数字,则将其复制到后缀的下一个元素。
    • 如果中缀中的当前字符是左括号,则将其压入堆栈。
    • 如果中缀中的当前字符是运算符,

      • 在栈顶弹出操作符(如果有的话),同时它们的优先级等于或高于当前操作符,并将弹出的操作符插入到后缀中。
      • 将中缀中的当前字符推入堆栈。
    • 如果中缀中的当前字符是右括号
      • 从堆栈顶部弹出运算符并将它们插入到后缀中,直到左括号位于堆栈顶部。
      • 从堆栈中弹出(并丢弃)左括号。

【问题讨论】:

  • 除非您感到自虐,否则谷歌搜索“递归下降”或(尤其是)“调车场算法”可能会很有帮助(如果您已经尝试使用其中之一,我很抱歉-- 至少乍一看我也不认为它是在实现)。
  • 我遵循了我刚刚在我的讲师给出的帖子中编辑的算法,但我似乎没有让它发挥作用。
  • 你应该与this person合作。他和你同时问了同样的问题。
  • 我们同班不同组。
  • 那么,在调试器中单步执行这段代码,它告诉你什么?不要告诉我你不知道调试器是什么或如何使用它,或者你没有尝试使用它或尝试过但无奈失败。来吧。你不能只用你的大脑来做,使用这个工具。

标签: c++ stack infix-notation postfix-notation


【解决方案1】:

因此,您的代码存在许多问题。我将发布什么(应该是)一个更正的解决方案,它有大量的 cmets 来解释正在发生的事情以及你在哪里犯了错误。前面有几件事:

  1. 我将使用std::string 而不是char *,因为它使事情变得更简洁,老实说,你应该在C++ 中使用它,除非你有很好的理由不这样做(例如互操作性带有C 库)。此版本还返回一个string,而不是将char * 作为参数。

  2. 我使用的是标准库中的堆栈,&lt;stack&gt;,它与您的自制堆栈略有不同。 top() 显示下一个元素 将其从堆栈中移除,pop() 返回 void,但从堆栈中移除顶部元素。

  3. 它是一个免费函数,不是类的一部分,但应该很容易修改 - 我用这种方式测试更容易。

  4. 我不相信您的运算符优先级表是正确的,但是,我会让您仔细检查一下。


#include <stack>
#include <cctype>
#include <iostream>

std::string convertToPostfix(std::string& infix)
{
    std::string postfix; //Our return string
    std::stack<char> stack;
    stack.push('('); //Push a left parenthesis ‘(‘ onto the stack.
    infix.push_back(')');

    //We know we need to process every element in the string,
    //so let's do that instead of having to worry about
    //hardcoded numbers and i, j indecies
    for(std::size_t i = 0; i < infix.size(); ++i) {

        //If it's a digit, add it to the output
        //Also, if it's a space, add it to the output 
        //this makes it look a bit nicer
        if(isdigit(infix[i]) || isspace(infix[i])) {
            postfix.push_back(infix[i]);
        }

        //Already iterating over i, so 
        //don't need to worry about i++
        //Also, these options are all mutually exclusive,
        //so they should be else if instead of if.
        //(Mutually exclusive in that if something is a digit,
        //it can't be a parens or an operator or anything else).
        else if(infix[i] == '(') {
            stack.push(infix[i]);
        }

        //This is farily similar to your code, but cleaned up. 
        //With strings we can simply push_back instead of having
        //to worry about incrementing some counter.
        else if(isOperator(infix[i]))
        {
            char operator1 = infix[i];
            if(isOperator(stack.top())) {
                while(!stack.empty() && precedence(operator1,stack.top())) {
                    postfix.push_back(stack.top());
                    stack.pop();
                }
            }
            //This shouldn't be in an else - we always want to push the
            //operator onto the stack
            stack.push(operator1);
        }    

        //We've hit a right parens - Why you had a for loop
        //here originally I don't know
        else if(infix[i] == ')') {
            //While top of stack is not a right parens
            while(stack.top() != '(') {
            //Insert into postfix and pop the stack
                postfix.push_back(stack.top());
                stack.pop();
            }
            // Discard the left parens - you'd forgotten to do this
            stack.pop(); 
        }
    }

    //Remove any remaining operators from the stack
    while(!stack.empty()) {
        postfix.push_back(stack.top());
        stack.pop();
    }
}

【讨论】:

  • 我添加了一些cmets作为答案(需要更多空间和格式的东西)-也许你想改进你的答案:)
  • @Stefan 谢谢,一切都很好。我已经更新了我的答案,希望这次没有错误(这是我为什么要编写测试的一个教训!)
【解决方案2】:

这基本上是对 Yuushi 回答的评论。

  • 外部 while(!stack.empty()) 循环错误。只需将其删除。 (保持c的循环体)。在函数结束时,检查堆栈是否为空,否则表达式有语法错误。
  • 正如 Yuushi 已经说过的,优先功能看起来很假。首先你应该给参数起一个更好的名字:一个是左边的操作符,另一个是右边的。 (现在你称之为precedence(rightOp, leftOp))。然后你应该记录结果的含义——如果a rOp b lOp c == (a rOp b) lOp c 现在你返回true(是的,操作符的顺序与你所说的不匹配——例如,“+”和“-”在两个订单中是不一样的)。
  • 如果你找到了一个新的操作符,你需要遍历堆栈中的旧操作符,例如在读取a - b * c之后你的输出是a b c并且堆栈是[- *]。现在你读到了+,你需要弹出两个操作符,得到a b c * -。即,输入 a - b * c + d 应导致 a b c * - d +

更新:附加完整解决方案(基于 Yuushi 的回答):

bool isOperator(char currentChar)
{
    switch (currentChar) {
    case '+':
    case '-':
    case '*':
    case '/':
    case '^':
    case '%':
        return true;
    default:
        return false;
    }
}

// returns whether a `lOp` b `rOp` c == (a `lOp` b) `rOp` c
bool precedence(char leftOperator, char rightOperator)
{
    if ( leftOperator == '^' ) {
        return true;
    } else if ( rightOperator == '^' ) {
        return false;
    } else if ( leftOperator == '*' || leftOperator == '/' || leftOperator == '%' ) {
        return true;
    } else if ( rightOperator == '*' || rightOperator == '/' || rightOperator == '%' ) {
        return false;
    }

    return true;
}

#include <stdexcept>
#include <cctype>
#include <sstream>
#include <stack>
std::string convertToPostfix(const std::string& infix)
{
    std::stringstream postfix; // Our return string
    std::stack<char> stack;
    stack.push('('); // Push a left parenthesis ‘(‘ onto the stack.

    for(std::size_t i = 0, l = infix.size(); i < l; ++i) {
        const char current = infix[i];

        if (isspace(current)) {
            // ignore
        }
        // If it's a digit or '.' or a letter ("variables"), add it to the output
        else if(isalnum(current) || '.' == current) {
            postfix << current;
        }

        else if('(' == current) {
            stack.push(current);
        }

        else if(isOperator(current)) {
            char rightOperator = current;
            while(!stack.empty() && isOperator(stack.top()) && precedence(stack.top(), rightOperator)) {
                postfix << ' ' << stack.top();
                stack.pop();
            }
            postfix << ' ';
            stack.push(rightOperator);
        }

        // We've hit a right parens
        else if(')' == current) {
            // While top of stack is not a left parens
            while(!stack.empty() && '(' != stack.top()) {
                postfix << ' ' << stack.top();
                stack.pop();
            }
            if (stack.empty()) {
                throw std::runtime_error("missing left paren");
            }
            // Discard the left paren
            stack.pop();
            postfix << ' ';
        } else {
            throw std::runtime_error("invalid input character");
        }
    }


    // Started with a left paren, now close it:
    // While top of stack is not a left paren
    while(!stack.empty() && '(' != stack.top()) {
        postfix << ' ' << stack.top();
        stack.pop();
    }
    if (stack.empty()) {
        throw std::runtime_error("missing left paren");
    }
    // Discard the left paren
    stack.pop();

    // all open parens should be closed now -> empty stack
    if (!stack.empty()) {
        throw std::runtime_error("missing right paren");
    }

    return postfix.str();
}

#include <iostream>
#include <string>
int main()
{
    for (;;) {
        if (!std::cout.good()) break;
        std::cout << "Enter the Arithmetic Expression: ";
        std::string infix;
        std::getline(std::cin, infix);
        if (infix.empty()) break;

        std::cout << "Postfix: '" << convertToPostfix(infix) << "'\n";
    }

    return 0;
}

【讨论】:

  • “for(;;)”有什么作用?
  • @Steven 它只是比写while (true)更短@
  • 根据你的precedence函数,a ^ b + c == ( a ^ b ) + c+ 运算符的优先级高于^。不应该a ^ b + c == a ^ ( b + c )吗?
  • @crisron a ^ b + c 绝对等于 (a^b) + c。 ^ 运算符具有最高优先级,因此它适用于操作数 a 和 b。然后在这种情况下将该操作的结果添加到 c。
【解决方案3】:

运算符优先级是这种情况下的问题。正确的运算符优先级降序为:

mul, div, mod   << *, /, % >>
add, sub        << +, - >>
XOR             << ^ >>

在上面的问题中考虑优先函数

bool ArithmeticExpression::precedence(char operator1, char operator2)
{
    if ( operator1 == '^' )
       return true;
    else if ( operator2 == '^' )
       return false;
    else if ( operator1 == '*' || operator1 == '/' )
       return true;
    else if ( operator1 == '+' || operator1 == '-' )
       if ( operator2 == '*' || operator2 == '/' )
          return false;
       else
          return true;
    return false;
}

对于operator1 中的每个值,operator2 的对应值都应根据上面提到的OPERATOR PRECEDENCE TABLE 检查优先级。未经适当比较,请勿返回任何值。

【讨论】:

    【解决方案4】:

    这是我的使用 C 进行多位数评估。

    #include <stdio.h>
    #include <math.h>
    #define MAX 50
    void push(char[],char);
    void in_push(double[], double);
    int pop();
    int prec(char);
    double eval(char[],int,double[]);
    int top = 0;
    void main() {
    double eval_stack[MAX];
    int op_count=0;
    char stack[MAX], exps[MAX], symbols[MAX];
    int i=0,j=0,len,check;
    while((symbols[i]=getchar())!='\n') {
    if(symbols[i]!=' ' || symbols[i]!='\t') {
    if(symbols[i]=='+' || symbols[i]=='-' || symbols[i]=='/' || symbols[i]=='*' || symbols[i]=='^')
    op_count++;
    i++;
    }
    }
    symbols[i]='#';
    symbols[++i]='\0';
    len = strlen(symbols);
    stack[top] = '#';
    for(i=0; i<=len; i++) {
    if(symbols[i]>='a'  && symbols[i]<='z') {
    exps[j]=symbols[i];
    j++;
    }
    switch(symbols[i]) {
    case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
    //if(symbols[i]>='a'  && symbols[i]<='z') {
    exps[j]=symbols[i];
    j++;
    break;
    case '+': case '-': case '*': case '/': case '^':
    exps[j++] = ' ';
    while(prec(symbols[i]) <= prec(stack[top])) {
    
                 exps[j] = stack[top];
                 pop();
                 //printf("\n\t\t%d\t\t%d\n", top,j);
                    j++;
    
    
    }
    if(prec(symbols[i]) > prec(stack[top])) {
    push(stack,symbols[i]);
    }
    break;
    case '(':
    push(stack,symbols[i]);
    break;
    case ')':
    while(stack[top]!='(') {
          exps[j] = stack[top];
           pop();
          j++;
    
    }
    pop();
    break;
    case '#':
    exps[j++] = ' ';
    while(stack[top]!='#') {
          exps[j] = stack[top];
           pop();
           j++;
    
    }
    pop();
    break;
    }
    }
    exps[j]='\0';
    printf("Postfix: %s", exps);
    for(i=0; i<j; i++)
    if(exps[i]=='a')
    check = 1;
    if(check!=1)
    printf("\nSolution: %.1f", eval(exps,j,eval_stack));
    }
    
    double eval(char exps[],int exps_len,double eval_stack[]) {
        int i; int len=exps_len,temp;
        double in_temp[MAX],t;
        int count,power,j,in_count;
        count=power=j=t=in_count=0;
        double result;
    for(i=0; i<len; i++) {
    switch(exps[i]) {
    case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
    in_temp[i] = exps[i]-'0';
    j=i+1;
    while(exps[j]>='0' && exps[j]<='9') {
    in_temp[j] = exps[j]-'0';
    j++; // 2
    }
    count = i; // 3
    while(in_temp[count]<='0' && in_temp[count]<='9') {
    power = (j-count)-1;
    t = t + in_temp[count]*(pow(10,power));
    power--;
    count++;
    }
    in_push(eval_stack,t);
    i=j-1;
    t=0;
    break;
    case '+':
    temp = pop();
    pop();
    result = eval_stack[temp] + eval_stack[temp+1];
    in_push(eval_stack,result);
    break;
    case '-':
    temp = pop();
    pop();
    result = eval_stack[temp] - eval_stack[temp+1];
    in_push(eval_stack,result);
    break;
    case '*':
    temp = pop();
    pop();
    result = eval_stack[temp] * eval_stack[temp+1];
    in_push(eval_stack,result);
    break;
    case '/':
    temp = pop();
    pop();
    result = eval_stack[temp] / eval_stack[temp+1];
    in_push(eval_stack,result);
    break;
    case '^':
    temp = pop();
    pop();
    result = pow(eval_stack[temp],eval_stack[temp+1]);
    in_push(eval_stack,result);
    break;
    }
    }
    return eval_stack[top];
    }
    int prec(char a) {
    if(a=='^')
    return 3;
    else if(a=='*' || a=='/' || a=='%')
    return 2;
    else if(a=='+' || a=='-')
    return 1;
    else if(a=='(')
    return 0;
    else
    return -1;
    }
    
    void push(char stack[], char ele) {
        if(top>=MAX) {
        printf("\nStack Overflow");
        exit(1);
        }
    stack[++top] = ele;
    }
    void in_push(double stack[], double ele) {
        if(top>=MAX) {
        printf("\nStack Overflow");
        exit(1);
        }
    stack[++top] = ele;
    }
    int pop() {
        if(top<0) {
        printf("\nStack Underflow");
        exit(1);
        }
    
    top = top - 1;
    return top;
    }
    

    【讨论】:

      【解决方案5】:

      C++实现如下:


        void infix2postfix(string s)
         {
           stack<char>st;
           for(int i=0; i<s.length(); i++)
           {
              if(isdigit(s[i]) || isalpha(s[i]))  cout<<s[i];
              else if( s[i]==')' )
              {
                 while(st.top()!='(')
                 {
                      cout<<st.top();
                      st.pop();
                 }
                st.pop();
              }
      
              else st.push(s[i]);
            }
         }
      

      【讨论】:

        【解决方案6】:

        这是我将中缀转换为后缀表达式的实现

        //Infix to Postfix conversion
        #include <bits/stdc++.h> 
        using namespace std; 
        
        bool isoperator(char c)                                            // function to check         if the character is an operator
        {
        if(c=='+'||c=='-'||c=='*'||c=='/'||c=='^')
            return true;
        else
            return false;
        }
        
        int precedence(char c)                // function to given the precedence of the operators
        {
        if(c == '^') 
            return 3; 
        else if(c == '*' || c == '/') 
            return 2; 
        else if(c == '+' || c == '-') 
            return 1; 
        else
            return -1; 
        }
        
        void infixToPostfix(string s)                          // funtion to convert infix to postfix
        {
        stack<char>st;
        string postfix;
        for(int i=0;i<s.length();i++)
        {
            if((s[i]>='a'&&s[i]<='z')||(s[i]>='A'&&s[i]<='Z'))         // if the given character is alphabet add it to the postfix string
                postfix+=s[i];
            else if(s[i]=='(')                                         // if the given character is "(" add it to the postfix string 
                st.push('(');
            else if(s[i]==')')                                         // if we find a closing bracket we pop everything from stack till opening bracket and add it to postfix string
            {
                while(st.top()=='(' && !st.empty())
                {
                    postfix+=st.top();
                    st.pop();
                }
                if(st.top()=='(')                                      // popping the opening bracket
                    st.pop();
            }  
            else if(isoperator(s[i]))                                 // if we find a operator
            {
                if(st.empty())                                        // if stack is empty add it to the stack
                    st.push(s[i]);
                else
                {
                    if(precedence(s[i])>precedence(st.top()))       // if operator precedence is grater push it in stack
                        st.push(s[i]);
                    else if((precedence(s[i])==precedence(st.top()))&&(s[i]=='^'))  // unique case for ^ operator
                        st.push(s[i]);
                    else
                    {
                        while((!st.empty())&&(precedence(s[i])<=precedence(st.top())))   // if precedence of st.top() is greater than s[i] adding it the postfix string
                        {
                            postfix+=st.top();
                            st.pop();
                        }
                        st.push(s[i]);       // pushing s[i] in the stack 
                    }
                }
            }
        }
        while(!st.empty())                  // popping the remaining items from the stack and adding it to the postfix string
        { 
            postfix+=st.top();
            st.pop();
        } 
        cout<<postfix<<endl;               // printing the postfix string
        }
        
        int main() 
        {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        string s;
        cin>>s;
        infixToPostfix(s); 
        return 0;
        } 
        

        示例:

        输入: a+b*(c^d-e)^(f+g*h)-i

        输出: abcd^efgh*+i-(^-(*+

        ps:如果你发现任何错误,请在下方评论:)

        【讨论】:

          猜你喜欢
          • 2015-09-13
          • 2015-09-12
          • 2011-06-13
          • 1970-01-01
          • 1970-01-01
          • 2013-11-08
          • 2013-03-28
          • 2015-04-19
          • 2012-04-03
          相关资源
          最近更新 更多