中缀表达式

1*(2+3)

这就是一个中缀表达式,运算符在数字之间,计算机处理前缀表达式和后缀表达式比较容易,但处理中缀表达式却不太容易,因此,我们需要使用shunting-yard Algorithm(调度场算法)来将中缀表达式转换为后缀表达式(即逆波兰表达式),然后求解。

上面的中缀表达式转后缀表达式后为:

1 2 3 + *

调度场算法

为了将中缀表达式转为后缀表达式,使用调度场算法,算法思想如下:

  准备两个栈,一个用于存放数字,一个用于存放操作符。

  从左到右遍历表达式,如果是数字,直接入栈。(注意数字可能是多位数甚至小数)

  如果是符号:

    如果栈为空,或者当前符号为‘ ( ’,或者栈顶为' ( ',直接入栈。

    如果当前运算符优先级高于栈顶运算符的优先级,则入栈。(注意是高于,等于也不行)

    如果当前运算符优先级不高于栈顶运算符,先从存符号的栈中取出一个操作符,从存数据的栈中取出两个数字,将它们做一次运算并将结果压入数据栈,最后再把当前运算符压入符号栈。

    如果当前符号是' ) ',不断重复上面划线部分的操作,直到取出的操作符是' ( '为止。

  表达式遍历完后,不断重复上面划线部分的操作,直到符号栈为空,此时数据栈还有一个数字,那就是原表达式的值。

这样就基本完成了。

这里再来讨论一下负号的处理,如何判断 ' - ' 是减号还是负号呢?

  如果' - '出现在表达式开头,一定是负号。

  如果' - '出现在数字后面,一定是减号。

  如果' - '出现在' ( '后面,一定是负号。

  如果' - '出现在' ) '后面,一定是减号。

综上可以看出,只要‘ - ’在表达式开头或者' ( '后面就可以判断为负号,但是判断之后怎么处理呢?

有两种办法,一种是在判断为负号的时候将数字0压入数据栈,然后将负号压入符号栈,可以看做是零减去一个数字。

另一种办法是,如果判断为负号,将下一个压入数据栈的数字乘上 -1。采用这种方法需要注意,如果括号内只有一个负数而没有计算式,按照上面的判断法则,下一个' ) '将直接被压入栈,从而导致奇怪的事情发生,只要在' ) '入栈前特判一下即可避免这种问题。(下面代码采用第二种方法)

C++代码实现如下

#include <iostream>
#include <string>
#include <cstring>
#include <stack>
using namespace std; int op[]; //确定运算符的优先级 /* string转数字 */
double toDig(string str) {
double n = , mag = 0.1;
for(int i = ; i < str.length(); i++) {
if(str[i]=='.') break;
mag *= ;
}
for(int i = ; i < str.length(); i++) {
if(str[i]=='.') continue;
n += mag*(str[i] - '');
mag /= ;
}
return n;
} /* 计算并返回结果 */
double getAns(double a, double b, char c) {
switch (c) {
case '+': return b+a;
case '-': return b-a;
case '*': return b*a;
case '/': return b/a;
}
} /* shunting-yard */
double shunting(string str) {
stack<double > iStk;
stack<char> strStk;
for(int i = ; i < str.length();) {
if( (str[i]>='' && str[i]<='') || (i==&&str[i]=='-') || (str[i]=='-'&&str[i-]=='(')) {
// 判断是否为数字或负号
string s1;
int f = ;
if(str[i]=='-') {
f=-;
i++;
}
while((str[i]>='' && str[i]<='') || str[i]=='.') {
s1 += str[i++];
}
iStk.push(f*toDig(s1));
} else { //不是数字或负号,则为操作符或括号
// 如果栈为空、或操作符为'('、或栈顶为'('、或当前操作符的优先级大于栈顶操作符,则操作符入栈
if(strStk.empty() || str[i]=='(' || strStk.top()=='(' || (str[i]!=')'&&op[str[i]] > op[strStk.top()])) {
if(str[i]==')' && strStk.top()=='(') strStk.pop(); //当前符号和栈顶是一对括号则消除它们
else strStk.push(str[i]);
}
else if(str[i] == ')') {
// 如果当前是')',则做运算直到栈顶是'('
char c = strStk.top();
while(c != '(') {
double a = iStk.top();
iStk.pop();
double b = iStk.top();
iStk.pop();
strStk.pop();
iStk.push(getAns(a,b,c));
c = strStk.top();
}
strStk.pop();
}
else {
// 否则,说明当前运算符优先级等于或小于栈顶运算符,将栈顶操作符取出做一次运算,将运算结果压栈,最后再将当前操作符入栈
double a = iStk.top();
iStk.pop();
double b = iStk.top();
iStk.pop();
char c = strStk.top();
strStk.pop();
iStk.push(getAns(a,b,c));
strStk.push(str[i]);
}
i++;
}
}
// 表达式处理完后,不断运算直到操作符空栈,此时数据栈剩下的一个数据就是最终结果
while(!strStk.empty()) {
double a = iStk.top();
iStk.pop();
double b = iStk.top();
iStk.pop();
char c = strStk.top();
strStk.pop();
iStk.push(getAns(a,b,c));
}
return iStk.top();
} int main() {
string s;
memset(op,,sizeof(op));
op['+'] = op['-'] = ;
op['*'] = op['/'] = ;
while(cin >> s) {
cout << shunting(s) << endl;
}
return ;
}

shunting-yard 调度场算法、中缀表达式转逆波兰表达式的更多相关文章

  1. c++实现将表达式转换为逆波兰表达式

    https://github.com/Lanying0/lintcode 所属: 数据结构->线性结构->栈 问题: 给定一个表达式字符串数组,返回该表达式的逆波兰表达式(即去掉括号). ...

  2. 关于利用STL栈求解四则中缀表达式以及中缀表达式转逆波兰表达式和逆波兰表达式的求解

    今天总结一下栈的一个重要应用---四则数学表达式的求解 数学表达式的求解是栈的一个重要的应用,在计算机的应用中 如果求解一个四则运算表达式,我们可能会直接写一个程序例如什么printf("% ...

  3. 调度场算法&&中缀表达式=>后缀表达式

    #include<stdio.h> #include<string.h> int main(void){ char ch,stro[1001],stack[1001]; int ...

  4. JavaScript实现计算后缀表达式(逆波兰表达式)以及将中缀表达式转为后缀表达式

    逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出.逆波兰表达式又叫做后缀表达式.这个知识点在数据结构和编译原理这两门课程中都有介绍,下面是一些例子: 正常的表达式 逆波兰表达式 a+b ...

  5. C#数据结构与算法系列(十):逆波兰计算器——逆波兰表达式(后缀表达式)

    1.介绍 后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后 2.举例说明 (3+4)*5-6对应的后缀表达式就是3 4 +5 * 6 - 3.示例 输入一个逆波兰表达式(后缀表达 ...

  6. 150. Evaluate Reverse Polish Notation逆波兰表达式

    [抄题]: Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are ...

  7. SDIBT2666——逆波兰表达式求值

    逆波兰表达式求值(栈和队列) Description 从键盘上输入一个逆波兰表达式,用伪码写出其求值程序.规定:逆波兰表达式的长度不超过一行,以@符作为输入结束,操作数之间用空格分隔,操作符只可能有+ ...

  8. 【python】Leetcode每日一题-逆波兰表达式求值

    [python]Leetcode每日一题-逆波兰表达式求值 [题目描述] 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说 ...

  9. noi1696 逆波兰表达式

    1696:逆波兰表达式 http://noi.openjudge.cn/ch0303/1696/ 总时间限制:  1000ms 内存限制:  65536kB 描述 逆波兰表达式是一种把运算符前置的算术 ...

随机推荐

  1. C#订阅与发布标准实现

    大概看了下C#官方提供的IObservable接口以及IObserver接口来实现发布和订阅,写的很标准,很有代表性,做下笔记,以后要是项目需要用到发布订阅再基于自己的需求改: public clas ...

  2. 2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)

    A. Airport Coffee 设$f_i$表示考虑前$i$个咖啡厅,且在$i$处买咖啡的最小时间,通过单调队列优化转移. 时间复杂度$O(n)$. #include<cstdio> ...

  3. jdbc连接oracle时报错 Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableC

    错误: Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; ...

  4. Appium-Python-Windows环境搭建笔记

    Appium版本:1.11.0 操作系统:Windows7-64位 开发语言:Python 3.7.2 测试应用平台:安卓 5.1.1 Appium服务端 一.JDK 也许你会觉得很奇怪,我搭建Pyt ...

  5. js文档就绪函数

    $(function(){ //执行的内容 }): $().ready(function(){ //执行的内容 }); $(document).ready(function(){ //执行的内容 }) ...

  6. 深度好文 | 在阿里做了5年技术Leader,我总结出了这些套路!

    导读:阿里巴巴高级技术专家云狄将为大家从管理的角度分享技术TL的核心职责,这其中包括团队建设.团队管理.团队文化.沟通与辅导.招聘与解雇等,希望与大家共同探讨.交流. 背景 互联网公司的技术团队管理通 ...

  7. Codeforces 1154D - Walking Robot - [贪心]

    题目链接:https://codeforces.com/contest/1154/problem/D 题解: 贪心思路,没有太阳的时候,优先用可充电电池走,万不得已才用普通电池走.有太阳的时候,如果可 ...

  8. Python extend()方法--list

    描述 extend()方法:在列表末尾追加可迭代对象中的元素. 语法 语法格式:list.extend(iterable) 参数 iterable:可迭代的对象,这里的对象可以是字符串.列表.元组.字 ...

  9. 包的初识和进阶&异常处理

    包 包是一种通过使用‘.模块名’来组织python模块名称空间的方式. 1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警 ...

  10. gitlab自动备份和定时删除

    GitLab数据手动备份1.GitLab默认备份目录为/var/opt/gitlab/backups,可以修改/etc/gitlab/gitlab.rb里面的默认存放备份文件目录,这里使用默认备份目录 ...