机试算法讲解: 第14题 实现一个简单计算器
2015-07-31 00:04
501 查看
/* 问题:简单的计算器,读入只含 +,-,*,/的非负整数计算式,计算表达式的值 输入: 若干测试用例,每个测试用例占1行,每行<=200个字符,整数和字符之间用一个空格分隔。无非法表达式。遇只含有0的一行时,结束输出 输出: 输出1行该表达式的值,保留2位小数 输入: (1 + 2) 1 2 + (4 + 2 * 5 - 7 / 11) 4 2 5 * + 7 11 / - 0 输出: 3.00 13.36 思路:用栈,后缀表达式,首先*和/的优先级较高,碰到需要优先处理,其实就是中缀表达式转换为后缀表达式,然后每次栈顶为运算符时, 取栈顶元素A,和次栈顶元素B,计算 B 运算符 A 即可,得到的计算结果再存入栈 问题转化为:中缀转后缀 好像是从右向左扫描 7 / 11 -> 关键: 1设定数字栈和运算符栈, 遇到数字直接压入数字栈中 遇到运算符,{若当前运算符#比栈顶运算符优先级小 或者 栈为空,则压入当前运算符 {否则,从数字栈中弹出栈顶元素A,次栈顶元素B,计算 B # A,将计算后的结果压入数字栈中 需要为该表达式设定运算符(和),两者的优先级最低,表示表达式的开始与结束 循环终止条件:运算符栈中仅剩2个运算符,并且栈顶运算符为")"时,比较优先级应该循环比较 2由于字符串中有空格,而scanf回跳过不处理,认为是下一次输出,因此对于含有空格或制表符的字符串用gets函数,而不是scanf char* gets(char* str); 3打印2位小数用printf("%.2f",i);不是%.2d,这表示整数 %n,mf:即输出总共n位,其中有m位小数,-号是右端补空格 4易错:11看成了2个1,应该以空格为分隔符(截取的字符串),来判定数字 */ #include <stdio.h> #include <stdlib.h> #include <stack> #include <string.h> #include <map> using namespace std; bool isNumber(char c) { if(' '==c) { return false; } char sNum[11] = {'0','1','2','3','4','5','6','7','8','9'}; int i = 0; while('\0'!=sNum[i]) { //if(c=sNum[i])//关键是==而不是= if(c==sNum[i]) { return true; } i++; } return false; } bool isOperator(char c) { if(' '==c) { return false; } char sOpe[7] = {'(',')','+','-','*','/'}; int i = 0; while('\0'!=sOpe[i]) { //if(c=sOpe[i]) if(c==sOpe[i]) { return true; } i++; } return false; } int my_atoi(char c) { switch(c) { case '0':return 0; case '1':return 1; case '2':return 2; case '3':return 3; case '4':return 4; case '5':return 5; case '6':return 6; case '7':return 7; case '8':return 8; case '9':return 9; default: return -999; } return -999; } int main(int argc,char* argv[]) { //设定优先级,+-一样,()一样,/*一样 map<char,int> mMap; mMap.insert(make_pair<char,int>('(',1)); mMap.insert(make_pair<char,int>(')',1)); mMap.insert(make_pair<char,int>('+',2)); mMap.insert(make_pair<char,int>('-',2)); mMap.insert(make_pair<char,int>('*',3)); mMap.insert(make_pair<char,int>('/',3)); char sInput[201]; //关键是1有空格,计算机就认为你重新输入了,必须扣除这种情况 //while(EOF!=scanf("%s",sInput)) while(gets(sInput)) { stack<char> stackOpe;//运算符栈 //为其添加开始标记( stackOpe.push('('); //stack<int> stackNum;//运算数栈 //易错,由于保留两位小数,数字栈的类型为double stack<double> stackNum; int i = 0; //必须在最后给其添加')' while('\0'!=sInput[i]) { /*如果运算符栈只剩2个元素,并且栈顶为,')',也退出循环 if(2==stackOpe.size() && ')'==stackOpe.top()) { break; } */ bool isNumbe = false; bool isOp = false; if(' '==sInput[i]) { i++; continue; } //获取连续的数字 int retn = 0; if(sInput[i] >= '0' && sInput[i] <= '9') { while(sInput[i] >= '0' && sInput[i] <= '9') { retn *= 10; retn += sInput[i] - '0'; isNumbe = true; i++; } i--;//确保拿到的是数字 } //其余默认为运算符 else { isOp = true; } //数字进数字栈 if(isNumbe || isNumber(sInput[i])) { //stackNum.push(my_atoi(sInput[i])); //stackNum.push(my_atoi(retn)); stackNum.push(retn); i++; //如果这是最后一个数字,则在运算符栈中添加')' if('\0'==sInput[i]) { sInput[i] = ')'; sInput[i+1] = '\0'; } } //运算符进运算符栈 else if(isOp || isOperator(sInput[i])) { //如果栈空,直接压入该运算符 if(stackOpe.empty()) { stackOpe.push(sInput[i]); i++;//计数器累加 } else { //如果当前运算符的优先级比栈顶运算符的优先级要高,则进栈,相同优先级不进栈 map<char,int>::iterator itFind = mMap.find(sInput[i]); if(itFind->second > (mMap.find(stackOpe.top()))->second) { stackOpe.push(sInput[i]); i++; } //如果是栈顶优先级高 >= 当前运算符优先级,则弹出栈顶元素和次栈顶元素,计算结果 1 + 2全部输入完成后,它没有计算,因此需要给定最低的两个运算符 else { double iBackNum = stackNum.top(); stackNum.pop(); double iFrontNum = stackNum.top(); stackNum.pop(); double iRes = 0.0; switch(stackOpe.top()) { case '+': iRes = (iFrontNum + iBackNum)*1.0; break; case '-': iRes = (iFrontNum - iBackNum)*1.0; break; case '*': iRes = (iFrontNum * iBackNum)*1.0; break; case '/': iRes = (iFrontNum / iBackNum)*1.0; break; //如果是"("或者是")" default: break; } //i++;//由于要循环遍历,计数器不变,仍停留在当前运算符,循环与前面的运算符比较 //将计算后的结果压入数字栈 stackNum.push(iRes); //易错,需要将栈顶高优先级操作符弹出,将当前低优先级操作进栈 stackOpe.pop(); //stackOpe.push(sInput[i]); if('('==stackOpe.top() && ')'==sInput[i]) { break; } }//else }//else }//else if }//for printf("%.2f\n",stackNum.top()); } system("pause"); getchar(); return 0; }
相关文章推荐
- JavaScript权威指南_145_第15章_脚本化文档_15.9-HTML表单-选择框和选项元素
- Https要点
- OC自学的第二天
- hdoj 2485 Destroying the bus stations 【最小割 + 最短路】
- 从C++到objective-c
- hdu5336 XYZ and Drops (模拟+vector删除第i个元素)
- 关于.NET C#调用Sqlite的总结一
- 如何在 Linux 上安装设备驱动程序
- 简单理解Python中的装饰器
- 将Python代码嵌入C++程序进行编写的实例
- 如何使用纯PHP实现定时器任务(Timer)
- PHP内核探索:哈希表碰撞攻击原理
- 如何把php5.3版本升级到php5.4或者php5.5
- PHP查看当前变量类型的方法
- PHP 前加at符合@的作用解析
- PHP代码实现爬虫记录――超管用
- PHP中filter函数校验数据的方法详解
- 详解Grunt插件之LiveReload实现页面自动刷新(两种方案)
- php自定义类fsocket模拟post或get请求的方法
- 如何使用Gitblog和Markdown建自己的博客