【菜鸟er】经典题目_逆波兰表示法

原创 2018年04月15日 18:14:03
#include <bits/stdc++.h>
using namespace std;
/**写在前面:
    对于所有容器,属性判断一定要放在操作判断的前面
    也就是说,top出的数据是否等于val这个条件一定要放在能否top后面,否则会异常
*/
stack<string> str;//生成期的临时符号栈
stack<int> num;//运算期的结果存储栈
queue<string> rbolan;//生成期的逆波兰栈
string s;//存储算式

void str_rbolan();
void rbolan_num();
int fsign(string a);

int main()
{
    str_rbolan();//中缀表达式转化成逆波兰表达式
    rbolan_num();//利用逆波兰表达式计算算式的数值
    int value = num.top();
    cout<<value<<endl;
    return 0;
}
void str_rbolan()
{
    cin>>s;
    for(int i=0;i<s.size();i++){//遍历算式
        string x;
        x.clear();//清空x
        if(isdigit(s[i])){//如果是数字
            //处理这个数值以字符串存入逆波兰队列
            while( i<s.size() && isdigit(s[i]) ){
                x = x + s[i];
                ++i;
            }
            i--;
            rbolan.push(x);//数值以字符串的形式压入逆波兰栈
        }

        else{//不是数字
            x = s[i];//处理x
            if(x == "(")//左括号压栈
                str.push(x);
            else if(x == ")"){//右括号出栈到左括号
                while( !str.empty() && str.top()!="(" ){
                    rbolan.push( str.top() );
                    str.pop();
                }
                str.pop();//pop出左括号
            }
            //下面处理运算符问题;分为两种;
            else if( !str.empty() && fsign(x) > fsign(str.top()) )
                str.push(x);
            else{
                while( !str.empty() && fsign(x) <= fsign(str.top() )){
                    rbolan.push(str.top());
                    str.pop();
                }
                str.push(x);
            }
        }
    }
    //把符号栈内的所有字符压入到逆波兰栈
    while( !str.empty() ){
        rbolan.push(str.top());
        str.pop();
    }
    return;
}
void rbolan_num()
{
    int x = 0;
    while(!rbolan.empty()){
        x = 0;
        string ss = rbolan.front();//获取第一个字符串进行分析
        if( isdigit(ss[0]) ){//如果是数字,则转化为十进制数值
            if(ss.size()>1){
                for(int j=0;j<ss.size();j++)
                    x = x*10 + (int)(ss[j]-'0');
                num.push(x);
            }
            else{
                x = ss[0]-'0';
                num.push(x);
            }
        }
        else{//为运算符
            int b = num.top(); num.pop();
            int a = num.top(); num.pop();

            if(ss == "+")   num.push(a+b);
            else if(ss == "-")   num.push(a-b);
            else if(ss == "*")   num.push(a*b);
            else if(ss == "/")   num.push(a/b);
        }
        rbolan.pop();//向下次操作数据移动
    }
}
int fsign(string a)
{
    if(a=="+") return 1;
    else if(a=="-") return 1;
    else if(a=="*") return 2;
    else if(a=="/") return 2;
}
/**运用逆波兰表示法求解字符串算式表达式的方法:
两个时期:生成期,运算期
生成期:
    技巧(定义一个临时符号栈,定义一个逆波兰栈(为了好用,直接定义成队列))
    遍历字符串中所有字符
    如果为数字,压入逆波兰栈
    如果为左括号,压入临时符号栈
    如果为右括号,从临时符号栈中取出符号压入逆波兰栈,直到碰到左括号(左括号直接丢弃)
    如果为运算符
        判断运算符与临时符号栈中的运算符优先级
            如果符号栈内运算符优先级大 取出到逆波兰栈,直到符号栈内符号小于待定存储的运算符
            否则直接压入符号栈。
    如果有剩余:依次取出压入逆波兰栈,此时临时符号栈作废。
运算期:
    补充定义一个结果栈
    依次遍历逆波兰栈
    如果取出数字字符:转化为int压入结果栈
    如果为运算符:
        从结果栈取出两个int
        利用运算符运算出结果
        把结果压入结果栈
*/
/**


1、将一个中序表达式转化成为逆波兰表达式。

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

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

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

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

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

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

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

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

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

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

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

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



2、利用逆波兰表达式求值

       利用逆波兰表达式求计算式的值其实很简单,正式因为这一点,所以逆波兰表达式才在编译原理中被用于计算一个表达式的值。

       下面来具体看看如何求一个逆波兰表达式的值:

       我们此时维护一个数据结果栈S3,我们将会看到该栈中最后存放的是最终的表达式的值。我们从左至右的遍历栈S1,然后按照下面的规则进行操作栈S3.

(1)如果遇到的是数字,那么直接将数字压入到S3中;

(2)如果遇到的是单目运算符,那么取S3栈顶的一个元素进行单目运算之后,将结果再次压入到栈S3中;

(3)如果遇到的是双目运算符,那么取S3栈顶的两个元素进行,首先出栈的在左,后出栈的在右进行双目运算符的计算,将结果再次压入到S3中。

       按照上面的三个规则,遍历完整个栈S1,那么最后S3中的值就是逆波兰表达式的值了,所以我们可以看出来使用逆波兰表达式进行求值是很简单的,只有两种操作要么是直接压栈,要么是运算之后将结果压栈。
*/

java:逆波兰表示法(后缀表达式)

用逆波兰表示法计算算术表达式的值。有效运算符为+,-,*,/。每个操作数可以是整数或另一个表达式。例子: ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9...
  • sinat_35803474
  • sinat_35803474
  • 2017年04月12日 13:08
  • 425

数据结构——逆波兰表示法

没想到第一次写数据结构就把我折腾死了呀~ 我看的是一本AOJ的书,然后以后的算法也是跟着书的目录来~ 题目的话会结合TOJ的一起写,可以对照着看哦~ 这个逆波兰表示法我就不多讲了,AOJ我用的堆栈...
  • TheWise_lzy
  • TheWise_lzy
  • 2017年01月30日 18:11
  • 1151

波兰表示法与逆波兰表示法(前缀、中缀、后缀表达式)

1、为什么要把中缀表达式转化为后缀,前缀? 计算机没法计算带有括号,以及区分优先级的表达式,或者说很难计算。使用后缀,前缀,消除了括号和优先级。 2、计算机如何计算后缀,前缀表达式? 计算后缀:...
  • le119126
  • le119126
  • 2016年07月11日 22:15
  • 1579

逆波兰表示法RPN 实现

逆波兰式的解释 逆波兰记法中,操作符置于操作数的后面。例如表达“三加四”时,写作“3 4 +”,而不是“3 + 4”。如果有多个操作符,操作符置于第二个操作数的后面,所以常规中缀记法的“3- 4...
  • u014713819
  • u014713819
  • 2014年04月16日 08:55
  • 666

波兰表示法与逆波兰表示法

它们都是对表达式的记法,因此也被称为前缀记法、中缀记法和后缀记法。它们之间的区别在于运算符相对与操作数的位置不同:前缀表达式的运算符位于与其相关的操作数之前;中缀和后缀同理。...
  • u011514810
  • u011514810
  • 2017年06月30日 14:04
  • 340

逆波兰法求解数学表达示(C++)

主要是栈的应用,里面有两个函数deleteSpace(),stringToDouble()在我另一篇博客当中:对string的一些扩展函数。        本程序只是基本的功能实现,没有差错控制。 ...
  • Walker19900515
  • Walker19900515
  • 2015年07月01日 14:41
  • 735

波兰表示法和逆波兰表示法的转换--Java

笔试题算法实现最近有很多笔试算法题,碰到了一道很陌生的:波兰表示法和逆波兰表示法的转换,用java代码实现了一下,题解给的实例跑通了,不知道其他的怎么样。 题干如下:思路 从后向前遍历输入的字符数组...
  • CHWYH
  • CHWYH
  • 2016年09月06日 16:57
  • 433

【数据结构】逆波兰表示法(RPN):中缀表达式转后缀表达式

利用栈来实现中缀表达式转后缀表达式。
  • hujingshuang
  • hujingshuang
  • 2015年11月06日 10:33
  • 1749

ER模型详解-陈氏模型

转载自: http://blog.163.com/magicc_love/blog/static/18585366220142125836878/Entity Relationship Model ...
  • zoujunjie202
  • zoujunjie202
  • 2016年03月25日 19:48
  • 4104

逆波兰表示法

逆波兰记法中,操作符置于操作数的后面。例如表达“三加四”时,写作“3 4 +”,而不是“3 + 4”。如果有多个操作符,操作符置于第二个操作数的后面,所以常规中缀记法的“3 - 4 + 5”在逆波兰记...
  • stephenluu
  • stephenluu
  • 2014年04月09日 01:42
  • 933
收藏助手
不良信息举报
您举报文章:【菜鸟er】经典题目_逆波兰表示法
举报原因:
原因补充:

(最多只允许输入30个字)