codevs 3066 中缀转后缀 ——栈


题目描述 Description

给你一个中缀表达式,请你转换成后缀表达式

输入描述 Input Description

一个中缀表达式

输出描述 Output Description

一个后缀表达式

样例输入 Sample Input

((5+7)/3*7-(3*2))+(7-3)*3+2*5+4*5+1*6+1*5

 

样例输出 Sample Output

57+3/7*32*-73-3*+25*+45*+16*+15*+

 

数据范围及提示 Data Size & Hint

好好想,亲们!

我想说的是:这题是没有数据范围的,但是里面的数字都是int范围的正整数,表达式求出结果也一定是int范围的整数,尽管...你不需要求的。

某种方法:

平常我们书写的表达式称为中缀表达式,因为它将运算符放在两个操作数中间,许多情况下为了确定运算顺序,括号是不可少的,而中缀表达式就不必用括号了。

后缀标记法:书写表达式时采用运算紧跟在两个操作数之后,从而实现了无括号处理和优先级处理,使计算机的处理规则简化为:从左到右顺序完成计算,并用结果取而代之。

例如:8–(3+2*6)/5+4可以写为:8 3 2 6*+5/–4+

其计算步骤为:8  3   2 6  *  +  5  /  –  4  +

              8 3  12  + 5  /  – 4  +

              8 15  5  / –  4  +

              8 3  –  4  +

              5 4  +

 

表达式知识: 

表达式的三种形式:

中缀表达式:运算符放在两个运算对象中间,这是我们书写的时候最熟悉的一种形式,如:(2+1)*3

后缀表达式:不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:2 1 + 3 *

前缀表达式:同后缀表达式一样,不包含括号,运算符放在两个运算对象的前面,如:* + 2 1 3

 

将一个中序表达式转化成为后缀表达式方法

       首先维护的是两个栈,我们这里暂且称为S1和S2,S1中的结果最后存的就是逆波兰表达式,S2中将用于暂时存放运算符并且在最终形成逆波兰表达式的时候,该栈是会清空的。下面我们看看怎样具体的形成逆波兰表达式。

       在此首先定义一下运算符的优先级关系,从小到达排序,相同优先级没有用逗号隔开:(,+-,*\,负号,)。

       从左至右遍历一个给定的中序表达式,也就是我们常规的数学计算的表达式。

(1)如果遇到的是数字,我们直接加入到栈S1中;

(2)如果遇到的是左括号,则直接将该左括号加入到栈S2中;

(3)如果遇到的是右括号,那么将栈S2中的运算符一次出栈加入到栈S1中,直到遇到左括号,但是该左括号出栈S2并不加入到栈S1中;

(4)如果遇到的是运算符,包括单目运算符和双目运算符,我们按照下面的规则进行操作:

          (4-1)如果此时栈S2为空,则直接将运算符加入到栈S2中;

          (4-2)如果此时栈S2不为空,当前遍历的运算符的优先级大于等于栈顶运算符的优先级,那么直接入栈S2;

          (4-3)如果此时栈S2不为空,当前遍历的运算符的优先级小于栈顶运算符的优先级,则将栈顶运算符一直出栈加入到栈S1中,直到栈为空或者遇到一个运算符的优先级小于等于当前遍历的运算符的优先级,此时将该运算符加入到栈S2中;

(5)直到遍历完整个中序表达式之后,栈S2中仍然存在运算符,那么将这些运算符依次出栈加入到栈S1中,直到栈为空。

       按照上面的五条操作反复进行完成,那么栈S1中存放的就是逆波兰表达式。

题目分析:本题只需要输出,不需要计算,所以不需要保存s1,按照上述方法,将s2出栈的时候输出即可。

 

#include<stdio.h>

#include<string.h>

#include<stack>

using namespace std;

stack<int> s;

char a[1000000];

int len;

int first[64];//存储++*/的优先级

int main()

{

         freopen("in.txt","r",stdin);

         first['+']=first['-']=1;

         first['*']=first['/']=2;

   scanf("%s",a);

   len=strlen(a);

    for(inti=0;i<len;i++){

       if(a[i]>=48&&a[i]<=57) //0-9数字本来就是按顺序的,输出

          printf("%c",a[i]);

        else{

                 switch(a[i]) {

                           case '(':{s.push('(');break;}

                           case ')':{

                                            while(!s.empty()&&s.top()!='(')       {

                                                     printf("%c",s.top())  ;

                                                     s.pop();

                                        }

                                               if(!s.empty()&&s.top()=='(')s.pop();       

                                               break;

                                     }

                                     case'+':case'-':{//低优先级

                                               while(!s.empty()&&s.top()!='(')       {

                                                                 printf("%c",s.top())  ;

                                                                 s.pop();

                                                                 }

                                               s.push(a[i]);

                                               break;

                                     }

                                     case'*':case'/':{//高优先级,入栈

                                            

                                                  while(!s.empty()&&s.top()!='('&&first[a[i]]<=first[s.top()]){

                                                                 printf("%c",s.top())  ;

                                                                 s.pop();

                                                                 }

                                               s.push(a[i]);

                                               break;

                                     }

                            }                

                   }

                    

    }

   while(!s.empty())

    {

   printf("%c",s.top());

    s.pop();

    }

    return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值