最近在看九度上面的题目,其中一道题本以为比较简单,但花了不少时间,题目如下:
我的思路是先读入一个字符串,再将字符串里面的数字和运算符号分别提取出来,最后根据运算的先后顺序计算得到最后的结果,程序清单如下:
#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];
else
tmpresult = 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];
else
restmp = 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 1001
double 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++真是博大精深!