最近在看九度上面的题目,其中一道题本以为比较简单,但花了不少时间,题目如下:
题目1019:简单计算器
我的思路是先读入一个字符串,再将字符串里面的数字和运算符号分别提取出来,最后根据运算的先后顺序计算得到最后的结果,程序清单如下:
#include<iostream>
#include<vector>
#include<string>
#include<cmath>
#include<iomanip>using namespace std;string skipblacks(string str) //忽略空格
{string return_str="";int length=str.length();for(int i=0;i<length;i++)if(str[i]!=' ')return_str+=str[i];return return_str;
}string str_dele(string s,int m) //删除字符串str的第m个字符
{int len=s.length(); char temp_str[100];if(m>len)cout<<"删除的位置不对!"<<endl;else{int j = 0;for(int i = 0;i<s.size();i++){if(i==m-1) continue;else temp_str[j++]=s[i];}}for(int i=0,j=0;j<len-1;)s[j++]=temp_str[i++];string sn = "";for(int i = 0;i<s.size()-1;++i)sn += s[i];return sn;
}vector<double> renew(vector<double> num,double tmpresult,int i)
{vector<double> vnew;for(int j = 0;j<i;++j)vnew.push_back(num[j]);vnew.push_back(tmpresult);if(i < num.size()-2)for(int j = i + 2;j<num.size();++j)vnew.push_back(num[j]);return vnew;
}vector<char> clearchch(vector<char> vch) //去除乘号除号
{vector<char> nvch;for(int i = 0;i<vch.size();++i)if(vch[i] != '*'&&vch[i] != '/')nvch.push_back(vch[i]);return nvch;
}int main()
{string str;vector<double> result;//保存结果while(getline(cin,str)){if(str == "0")break;vector<char> vch;vector<int> vi;string s = skipblacks(str);//忽略字符串中的空格for(int i = 0;i<s.size();++i){if((s[i]=='+')|(s[i]=='-')|(s[i]=='*')|(s[i]=='/'))vch.push_back(s[i]); //保存运算符哈else if(s[i]>='0'&&s[i]<='9')vi.push_back(s[i]-'0'); //保存数字}string ns = s;vector<double> vpos;//记录运算符号在原字符串中的位置vector<double> vnum;//记录每个数的位数for(int i = 0;i<vch.size();++i){size_t pos = ns.find(vch[i]);ns = str_dele(ns,pos+1);vpos.push_back(pos+i+1);}vnum.push_back(vpos[0]-1);for(int i = 0;i<vpos.size()-1;++i)vnum.push_back(vpos[i+1]-vpos[i]-1);double tmpsum = 0;for(int i = 0;i<vnum.size();++i)tmpsum += vnum[i];double tmps = s.size()-vch.size()-tmpsum;vnum.push_back(tmps);vector<double> num;//将vi转化为数字double tmpn = 0;for(int i = 0;i<=vch.size();++i){double sum = 0;tmpn += vnum[i];for(int j = 0;j<vnum[i];++j)sum += vi[j+tmpn-vnum[i]]*pow(10,vnum[i]-1-j);num.push_back(sum);}vector<double> vnew = num;int ccnt = 0;for(int i = 0;i<vch.size();++i){if((vch[i] == '*')|(vch[i] == '/')){double tmpresult;if(vch[i] == '*')tmpresult = num[i]*num[i+1];elsetmpresult = num[i]/num[i+1];vnew = renew(vnew,tmpresult,i-ccnt);//更新结果++ccnt; //统计已经计算过多少个*和/。}}vector<char> nvch = clearchch(vch);//去除乘号和除号只剩下加减号double restmp = vnew[0];for(int i = 0;i<nvch.size();++i){if(nvch[i] == '+')restmp = restmp + vnew[i+1];elserestmp = restmp - vnew[i+1];}result.push_back(restmp);}for(int i = 0;i<result.size();++i)cout<<fixed<<setprecision(2)<<result[i]<<endl; //保留两位小数system("pause");return 0;
}
演示结果如下:
从结果可以看到,实现了题设的要求,但是奇怪的是提交代码之后显示“ Wrong Answer”,暂时还不知道是啥原因。
在编写这个程序的过程中,遇到很多细节问题和一些编程基本知识,在这里总结一下:
(1)保留小数点位数,参见博客C++ 标准输出控制小数点后位数的方法;
(2)实现“忽略一个字符串里的空格”和“删除字符串中某个字符或某个位置的字符”这样类似的功能可以编写一个函数进行实现;
(3)在进行除法运算时,要注意整形数据到双精度形数据过程可能会损失掉小数部分,可以先将整形数据转化为双精度形数据再进行计算;
(4)读取整行数据用getline(cin,str)实现。
此外,我在九度论坛里也看到很多特别简洁的答案,深感佩服,其中贴出一个代码如下:
#include "stdio.h"
#include "string.h"
#define MAX 1001double stack[MAX];
int tail;int main(){int a;while(scanf("%d ",&a)&&a!=0){tail=0;stack[++tail]=1.0*a;//tail始终指向末尾数字位置//1.入栈所有数据(如果遇到*/号,只更新栈尾)char ch1,ch2;while(scanf("%c %d%c",&ch1,&a,&ch2)!=EOF){if(ch1=='+'){stack[++tail]=1.0*a;//push}else if(ch1=='-'){stack[++tail]=-1.0*a;//push neg}else if(ch1=='*'){stack[tail]=stack[tail]*a;//update tail}else if(ch1=='/'){stack[tail]=stack[tail]/(double)a;//updata tail}if(ch2!=' ')break; }//2.把栈里头的东西全部加起来,求和double result=0;for(int i=1;i<=tail;i++)result+=stack[i];printf("%.2lf\n",result);}return 1;
}
代码只有30多行,却实现了题目所要求的功能,感觉C++真是博大精深!