计算四则表达式(中缀式转后缀式,然后计算结果)
1. 目的:写一个程序,从键盘输入一个合法的四则运算表达式,输出计算结果;
2. 实现原理:将表达式先由中缀式转为后缀式,然后利用栈计算表达式结果;
3. 实现代码:
版本1:
#include <iostream>
#include <stack>
#include <string>
using namespace std;
const int SIZE = 100;bool isOperator( char op )
{switch(op){case '+':case '-':case '*':case '/':return true;default:return false;}
}int priority( char op ) // 比较运算符优先级
{int value = -1;switch(op){case '#':value = -1;break;case '(':value = 0;break;case '+':case '-':value = 1;break;case '*':case '/':value = 2;break;}return value;
}// 中缀式转换为后缀式
// 把中缀表达式转换为后缀表达式,返回后缀表达式的长度(包括空格)
int preToPostExp( string exp, char postExp[SIZE], int &len )
{stack<char> opSt; opSt.push('#');int i = 0;int j = 0;while( exp[i] != '#' ){if( exp[i] >= '0' && exp[i] <= '9' || exp[i] == '.' ){postExp[j++] = exp[i];len++;} else if( exp[i] == '(' )// 遇到“(”不用比较直接入栈{opSt.push(exp[i]);}else if( exp[i] == ')' )//遇到右括号将其对应左括号后的操作符(操作符栈中的)全部写入后缀表达式 {while( opSt.top() != '(' ){postExp[j++] = opSt.top();opSt.pop();len++;}opSt.pop(); //将'('出栈 将“(”出栈,后缀表达式中不含小括号 }else if( i == 0 && (exp[i] == '+' || exp[i] == '-') ) //表明第一个数为正负号{postExp[j++] = exp[i];len++;} else if( isOperator(exp[i]) ){postExp[j++] = ' '; //用空格隔开操作数len++;//当前的操作符小于等于栈顶操作符的优先级时,将栈顶操作符写入到后缀表达式,重复此过程 while( priority(exp[i]) <= priority( opSt.top() ) ){postExp[j++] = opSt.top();opSt.pop();len++;}opSt.push(exp[i]); // 当前操作符优先级大于栈顶操作符的优先级,将该操作符入栈 }i++;} while( opSt.top() != '#' ) // 将所有的操作符加入后缀表达式{postExp[j++] = opSt.top();opSt.pop();len++;}return 0;
}double read_number(char str[],int *i)
{ double x=0.0; int k = 0; while(str[*i] >='0' && str[*i]<='9') // 处理整数部分 { x = x*10+(str[*i]-'0'); (*i)++; } if(str[*i]=='.') // 处理小数部分 { (*i)++; while(str[*i] >= '0'&&str[*i] <='9') { x = x * 10 + (str[*i]-'0'); (*i)++; k++; } } while(k!=0) { x /= 10.0; k--; } return x;
} // 计算后缀表达式结果
double computePostExp( char post[SIZE] )
{stack<double> stack; // 操作数栈 double x1 = 0;double x2 = 0;bool flag = false;int i = 0;double d = 0;while( post[i] != '\0' ){if( post[i] >= '0' && post[i] <= '9' ){d = read_number(post,&i);if(flag) // 第一个数为负数{d = -d;flag = false;}stack.push(d);} else if(post[i] == ' ' )i++; else if (post[i] =='+') { x2 = stack.top(); stack.pop();x1 = stack.top(); stack.pop();stack.push(x1+x2); i++; } else if( post[i] == '-' && i == 0 ) //表明第一个数为负数,方便计算-1+2*3{flag = true;i++;}else if (post[i] =='-') { x2 = stack.top(); stack.pop();x1 = stack.top();stack.pop(); stack.push(x1-x2); i++; } else if (post[i] =='*') { x2 = stack.top(); stack.pop();x1 = stack.top(); stack.pop();stack.push(x1*x2); i++; } else if (post[i] =='/') { x2 = stack.top(); stack.pop();x1 = stack.top(); stack.pop();stack.push(x1/x2); i++; } } return stack.top();
}int main()
{string exp = "";char postExp[SIZE]; // 保存后缀式结果 cout << "输入表达式(中缀,以#结束):"; cin >> exp; // 以#号结束int len = 0;preToPostExp( exp, postExp, len );postExp[len] = '\0';cout << "后缀表达式为:";cout << postExp << endl;cout << "\n由后缀表达式计算出的数值结果: "; cout << computePostExp(postExp) << endl;system("pause");return 0;
}
/*
中缀式变后缀式算法:
反复读取输入内容直到结束为止
如果是数字直接入栈
否则如果是'('就等待处理括号里面的
否则如果是')'就倒回来处理直到左括号为止的全部运算
否则就是普通运算符(+,-,*,/)
反复看那些暂存的未处理的运算符,只要优先级不比本运算符低就处理(入栈)
暂存本运算符
反复取出栈中的剩余运算符并保存,直到栈无运算符
*/
4. 结果:
转载地址:
http://blog.csdn.net/geekcoder/article/details/6829386
注:相对于转载的地址中的代码,改进之一就是能够计算第一个操作数为负数的情况,即计算类似:-1+2*3的表达式
版本2:
#include <iostream>
#include <stack>
#include <string>
using namespace std;/*
表达式计算思路一:
1)准备两个栈:数据栈和运算符栈;
反复读取表达式:(2,3,4步)
2)如果是数,入数据栈;
3)如果是左括号,入运算符栈,如果是右括号,反复从运算符栈顶取运算符和从数据栈里取两个数据进行计算,并把结果入数据栈,直到遇到栈顶是左括号为止。
4)如果是运算符op,先跟栈顶的运算符比,只要不高于栈顶优先级,就取出栈顶的运算符和数据栈的两个数据进行计算,并把结果入数据栈,直到高于栈顶运算符优先级或者遇到左括号或者运算符栈空为止,此时把op入栈;
5)处理栈中的运算符:取出栈顶的运算符和数据栈的两个数据进行计算,并把结果入数据栈,直到运算符栈空为止;
6)这时数据栈中的数据就是计算结果。
*/
class Exp
{private:stack<char> ops;stack<double> ds;double v, lh, rh; // 计算结果和临时操作数变量 char op; //运算符 public:double calinput()//读取并计算表达式直到结束为止{do{readdata();skipspace(); //跳过空白 }while( readop() );calremain(); //处理栈中剩余的运算符return v; } void readdata() //在该出现数据的时候可能出现'(' {// 如1+((2*3)) 左括号可能是多个 while( !(cin>>v) ) //读取数据失败,此时读取应该是'(',而v为double类型 {cin.clear();cin >> op; //读取'('if( op != '(' ){throw string("在该出现数值的地方出现了") + op; } ops.push(op); //左括号入栈 }ds.push(v);return;}void skipspace(){while( cin.peek() == ' ' || cin.peek() == '\t' ) //cin.peek只看不取走{cin.ignore(); //丢掉一个空白字符 } }bool readop() //读取运算符,可能出现右括号或者换行符(表达式结束) {//如(2*(3+4/(4-5))),右括号可能是多个 while( (op = cin.get() ) == ')' ){while( ops.top() != '(' ){rh = ds.top(); //取左操作数 ds.pop(); lh = ds.top();//取右操作数 ds.pop();ds.push( cal( lh, ops.top(), rh ) ); //计算并入栈ops.pop(); //取走运算符 } ops.pop(); //丢弃'(' }if( op == '\n' ){return false;}if( strchr("+-*/", op ) == NULL ) //无效运算符 {throw string("无效运算符") + op; }while( !ops.empty() && ops.top() != '(' && !prior( op, ops.top() ) ){rh = ds.top(); ds.pop();lh = ds.top(); ds.pop();ds.push( cal( lh, ops.top(), rh ) ); //计算并入栈ops.pop(); //取走运算符 }ops.push(op);return true;} void calremain(){while( !ops.empty() ){rh = ds.top(); ds.pop();lh = ds.top(); ds.pop();ds.push( cal( lh, ops.top(), rh ) ); //计算并入栈ops.pop(); //取走运算符 }if( ds.size() != 1 ){throw string("无效的表达式"); }v = ds.top();ds.pop();return;}double cal( double lh, char op, double rh ){return op == '+'?lh+rh:op=='-'?lh-rh:op=='*'?lh*rh:lh/rh;}bool prior( char o1, char o2 )//若o1比o2优先级高返回true,否则返回false {return o1 != '+' && o1 != '-' && o2 != '*' && o2 != '/';}};int main()
{Exp e;try{cout << e.calinput() << endl;}catch( const string &e ){cout << e << endl;}system("pause");return 0;
}
输出结果:
计算四则表达式(中缀式转后缀式,然后计算结果)相关推荐
- c 语言表达式求值中缀变后缀,表达式求值关于中缀式转后缀式的问题!
已结贴√ 问题点数:10 回复次数:6 表达式求值关于中缀式转后缀式的问题! 本人看资料的时候遇到一段代码,这段代码中转为后缀式的优先级那句不明白,请大神赐教,代码如下(c语言) #include # ...
- nyoj-257-郁闷的C小加(一 )中缀式变后缀式
题目链接:here~~~~~~~ 今天看了此题,感觉栈和队列很好用,进一步深入了解 一个算术表达式,含有数字(为简化处理,数字只有一位),运算符:+.-.*,以及括号,求表达式的值. 给出的表达式是一 ...
- NYOJ 467 中缀式变后缀式
中缀式变后缀式 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 人们的日常习惯是把算术表达式写成中缀式,但对于机器来说更"习惯于"后缀式,关于算术表达 ...
- java自动递增前缀式和后缀式区别
java自动递增前缀式和后缀式区别 java自动递增(自动递减)前缀式表达式 '++' 操作符位于变量或表达式的前面,而后缀式表达式'++'位于变量或表达式的后面,Example: 前缀式: ++i: ...
- nyoj 1272 表达式求值(中缀式转后缀式)
表达式求值 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 假设表达式定义为: 1. 一个十进制的正整数 X 是一个表达式. 2. 如果 X 和 Y 是 表达式,则 X+ ...
- 算术表达式的前缀式、中缀式、后缀式相互转换
中缀表达式(中缀记法) 中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间.中缀表达式是人们常用的算术表示方法. 虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀 ...
- 语法树,前缀式,中缀式,后缀式
前序遍历:根左右 中序遍历:左根右 后序遍历:左右根 前缀式:+AB 中缀式:A+B 后缀式:AB+ 例题一: 前序遍历(前缀式):- + 4 * 1 - 5 2 / 6 3 根在前,从最后开始:-5 ...
- 逆波兰式(后缀式)详解
原表达式:a*(b*(c+d/e)-f)# /* # 为表达式结束符号*/ 后缀式:abcde/+*f-*# 为运算符定义优先级:# ( + - * / ** -1 ...
- 前缀式与后缀式的差别
文章出处: http://blog.sina.com.cn/s/blog_5ca785c30100bb89.html websense的一道笔试题,问++i为什么比i++效率高. 有有心人详细而全面的 ...
- java 中缀式转后缀式
import java.util.Stack; import java.util.regex.*; public class StringToArithmetic { private StringTo ...
最新文章
- DLM:微信大规模分布式n-gram语言模型系统
- 电脑前面的插孔没声音怎么设置_手机没声音是怎么回事
- 4+5的值是python_Python基础:数据类型-数字(5)
- 在Windows XP系统登录Active Directory域
- Jupyter Notebook 入门指南
- 中connect怎么用_烘焙中的各种酒,到底该怎么用?
- 蓝色起源起诉NASA,不服其将月球着陆器合同授予SpaceX
- php orm 内存泄漏,Lavarel Eloquent ORM常驻进程下的内存溢出问题
- 软核、固核、硬核的区别
- python创建子窗口_python GUI编程(Tkinter) 创建子窗口及在窗口上用图片绘图实例
- 无人驾驶入门1:无人驾驶概览
- (APP测试三板斧)第一板:Xposed+JustTrustMe绕过SSL Pining
- 在企业中采用知识管理工具的好处
- Rate 函数在PromQL 查询中的使用
- 拜登签署芯片法案后,英特尔股票的前景如何?
- 单纯技术背景已不吃香 MBA管理能力更被招聘者看好
- Django推导Django内部模块:wsgiref与jinja2
- 微信分享按钮隐藏、显示问题和注意事项
- yii mysql 查询 类型转换_yii2.0数据库查询修改等方法
- 萌宠历险记html5游戏在线玩,7724萌宠历险记
热门文章
- 【智衡跨境电商shopee运营】Shopee平台流量入口有哪些?
- win7指定网络名不再可用
- FIsh论坛《零基础入门学习Python》| 第012讲 课后测试题及答案
- LaTeX插入参考文献教程 | 非BibTeX格式
- 南京大学计算机专业复试面试,南京大学计算机CS专业复试超全PPT及真题、面试内部资料(离散编译上机面试)...
- SpringBoot整合MyBatis(七)
- JavaScript函数传参原理详解——值传递还是引用传递
- 角度与弧度的转换 C语言
- python——平方根
- 详细介绍MATLAB导入文本文件、excel等数据文件