前,中,后缀表达式

转自:前,中,后缀表达式
前缀表达式,中缀表达式,后缀表达式都是四则运算的表达方式,用以四则运算表达式求值,即数学表达式的求值。比如一个简单的数学表达式 (1+2)-(3+4) 这是我们常见的数学表达式类型 即中缀表达式

  • 把这个表达式转化位前缀表达式(也称波兰式) -+12+34
  • 把这个表达式转化位后缀表达式(也称逆波兰式) 12+34±

为什么要将简单的中缀表达式转化为复杂的波兰式或逆波兰式
原因在于,简单的中缀表达式在用人的思维逻辑来看,确实简单,但在计算机看来中序表达式是非常复杂的结构,而相对而言,(逆)波兰式在计算机看来是非常简单的结构,因为计算机普遍采用的内存结构是栈式结构,而(逆)波兰表达式在其存储和计算上也采用的是栈的特性。
中缀表达式与后缀表达式的转换
1.建立一个栈,一个队列
2.从左至右顺序遍历中缀表达式。
3.遇到操作数时,直接压入队列
4.遇到运算符时:
  当遇到左括号或是栈为空,直接压栈
  当遇到右括号时,依次弹栈,直至栈顶是左括号,弹栈结束!期间所有的操作符按顺序入队
  当遇到操作符时,若栈顶是左括号,则直接入栈
          若栈顶是操作符,则比较两操作符优先级,若当前字符优先级较高,则压栈,若当前字
          符优先级小于等于栈顶运算符,则将栈顶运算符弹出并入队,继续与当前栈顶元素比较!
          直到当前运算符优先级高于栈顶运算符则入栈,或是遇到左括号或是栈为空,亦入栈!
5.遍历完所有字符后,弹出栈中仍剩有的操作符,并入队
6.依次出队即可达到相应的后缀表达式!

vector<string> mid2last(string str)
    {
        //简易版 中缀表达式转后缀,操作符只涉及+ -
        queue<string> q;
        stack<string> s;
        int n=str.size();
        int start=-1;
        for(int i=0;i<n;++i)
        {
            //记录操作数的首位
            if(str[i]>='0' && str[i]<='9')
            {
                if(start==-1)
                    start=i;
            }
            else
            {
                if(start!=-1)
                {
                    //将完整操作数入队
                    q.push(string(str.begin()+start,str.begin()+i));
                    //cout<<string(str.begin()+start,str.begin()+i);
                    start=-1;
                }
                //遇到空格则继续遍历
                if(str[i]==' ')
                    continue;
                //作括号直接入栈
                else if(str[i]=='(')
                    s.push("(");
                else if(str[i]==')')
                {
                    //右括号依次弹栈并入队,直至遇到左括号
                    string tmp=s.top();
                    s.pop();
                    while(tmp!="(")
                    {
                        q.push(tmp);
                        tmp=s.top();
                        s.pop();
                    }
                }
                else if(str[i]=='+')
                {
                    //遇到+号操作符,栈为空则直接进栈
                    if(s.empty())
                        s.push("+");
                    else
                    {
                        string tmp=s.top();
                        //栈顶为左括号亦直接进栈
                        if(tmp=="(")
                            s.push("+");
                        //由于操作符只有+ -,且优先级一样,那么遇到栈中不可能共存多个操作符
                        //因此栈顶为操作符时,直接弹栈并入队,然后将当前字符入栈
                        else if(tmp=="+" || tmp=="-")
                        {
                            s.pop();
                            s.push("+");
                            q.push(tmp);
                        }
                    }

                }
                else if(str[i]=='-')
                {
                    //遇到-号,同+号
                     if(s.empty())
                        s.push("-");
                    else
                    {
                         string tmp=s.top();
                        if(tmp=="(")
                            s.push("-");
                        else if(tmp=="+" || tmp=="-")
                        {
                            s.pop();
                            s.push("-");
                            q.push(tmp);
                        }
                    }

                }
            }

        }
        if(start!=-1)
        {
            //末尾可能还有操作数,将操作数入队
            q.push(string(str.begin()+start,str.end()));
        }
        while(!s.empty())
        {
            //弹出栈中剩余操作符入队
            q.push(s.top());
            s.pop();
        }
        vector<string> res;
        while(!q.empty())
        {
            //以一定的格式保存后缀表达式
            res.push_back(q.front());
            q.pop();
        }
        return res;
    }

后缀表达式值的计算
1.建立一个栈
2.从左到右顺序遍历后缀表达式
3.遇到操作数则直接进栈
4.遇到操作符,则依次弹出栈顶上的两个元素,对其进行运算,然后将运算结果进栈
5.重复 2,3,直至遍历完整个表达式,那么栈中将只剩下一个元素,它就是整个表达式的运算结果

int evalRPN(vector<string>& tokens) {
        if(tokens.empty())
            return 0;
        stack<int> helper;
        int n=tokens.size();

        for(int i=0;i<n;++i)
        {
            int num;
            //运用c++字符串流,将字符串转化为整数
            istringstream in(tokens[i]);
            in>>num;
            if(!in.fail())
            {
                //若当前字符串是操作数,则转化成功,将操作数入栈
                helper.push(num);
            }
            else
            {
                //若当前字符串是操作符,则转化失败

                //依次弹出两个栈顶元素
                int num1=helper.top();
                helper.pop();;
                int num2=helper.top();
                helper.pop();
                //判断操作符种类,进行数学运算并将运算结果入栈
                if(tokens[i]=="+")
                    helper.push(num2+num1);
                else if(tokens[i]=="-")
                    helper.push(num2-num1);
                else if(tokens[i]=="*")
                    helper.push(num2*num1);
                else if(tokens[i]=="/")
                    helper.push(num2/num1);

            }
        }
        return helper.top();
    }

前缀表达式在操作上与后缀表达式的几个不同点

  • 前缀表达式的所有遍历从右到左的!自然遇到括号的处理方式与后缀表达式是相反的
  • 在与中缀表达式的转化时,遇到操作符的处理方式是,与栈顶元素比较,若优先级大于等于栈顶运算符,就直接入栈,注意在后缀表达式中是大于。
发布了56 篇原创文章 · 获赞 67 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/leo187/article/details/90449903