第四次作业 计算器第二步
题目链接:
http://www.cnblogs.com/fzuoop/p/5326667.html
github链接:
https://github.com/MeKChen2/object-oriented/tree/master/Calculator-fourth homework
1.解题思路:
这次拿到的题目要求在第三次作业上进行修改,在看过学长在第三次作业上的评论后,我重新审了一次第三次的题目,发现我把题目理解错了。
在将第三次作业的代码改成五个文件的时候,出现了很多问题,无论用什么编译器都无法正常将代码分成五个文件。
所以,在进一步学习了栈的知识和浏览了许多博客后,我打算完全放弃第三次的代码来写第四次的作业。
表达式的计算思路:
1)准备两个栈:数据栈和运算符栈;反复读取表达式 。
2)如果是数,入数据栈;
3)如果是左括号,入运算符栈,如果是右括号,反复从运算符栈顶取运算符和从数据栈里取两个数据进行计算,并把结果入数据栈,直到遇到栈顶是左括号为止。
4)如果是运算符op,先跟栈顶的运算符比,只要不高于栈顶优先级,就取出栈顶的运算符和数据栈的两个数据进行计算,并把结果入数据栈,直到高于栈顶运算符优 先级或者遇到左括号或者运算符栈空为止,此时把op入栈;
5)处理栈中的运算符:取出栈顶的运算符和数据栈的两个数据进行计算,并把结果入数据栈,直到运算符栈空为止;
6)这时数据栈中的数据就是计算结果。
代码如下:
#include <iostream>
#include <stack>
#include <string>
#include <cstring>
using namespace std;
class Calculation
{
private:
stack<char> oper;
stack<double> shu;
double v,a,b;
char op; //运算符
public:
double calinput() //读取并计算表达式直到结束为止
{
do
{
readdata();
}
while(readop());
calsurplus(); //处理栈中剩余的运算符
cout << v << endl;
return 0;
}
void readdata() //读取数据
{
while(!(cin>>v)) //判断读取数据是否正常
{
cin.clear();
cin >> op;
oper.push(op);
}
shu.push(v);
return;
}
bool readop() //读取运算符
{
while((op = cin.get()) == ')')
{
while( oper.top() != '(' )
{
b = shu.top();
shu.pop();
a = shu.top();
shu.pop();
shu.push(cal(a, oper.top(), b)); //计算并入栈
oper.pop(); //取走运算符
}
oper.pop();
}
if(op == '\n')
{
return false;
}
while(!oper.empty() && oper.top() != '(' && !com( op, oper.top()))
{
b = shu.top();
shu.pop();
a = shu.top();
shu.pop();
shu.push(cal( a, oper.top(), b )); //计算并入栈
oper.pop(); //取走运算符
}
oper.push(op);
return true;
}
void calsurplus()
{
while(!oper.empty())
{
b = shu.top();
shu.pop();
a = shu.top();
shu.pop();
shu.push(cal( a, oper.top(), b )); //计算并入栈
oper.pop(); //取走运算符
}
v = shu.top();
shu.pop();
return;
}
double cal(double a, char op, double b)
{
if(op=='+')
return a+b;
else if(op=='-')
return a-b;
else if(op=='*')
return a*b;
else if(op=='/')
return a/b;
}
bool com(char c, char d) //若c比d优先级高返回true,否则返回false
{
if(c != '+' && c != '-' && d != '*' && d != '/')
return true;
else
return false;
}
};
int main()
{
Calculation e;
e.calinput();
system("pause");
return 0;
}
运行结果:
存在的问题:
这部分代码无法满足题目要求,即当输入-a时要输出表达式,本想写完主要代码再进行-a那步骤的修改,想了很久没有想出方法。
而且我定义的两个栈,一个是char,一个是double,所以没有用到sstream来将字符转换成数字。
改进:
剩下的三天时间,打算用其他方法再进行尝试,改进代码。
反思:
此次代码虽然没有通过第三次代码基础修改得到,但是这次我查阅学习了资料,自我感觉代码比之前第三次的要好了很多,第三次的代码用这次的方法也能更容易写出,现在来看第三次作业反而觉得很简单。以后的学习中应该先掌握好足够的知识,再进行做题,更有效果
参考资料:
http://www.nowamagic.net/librarys/veda/detail/2306
http://blog.csdn.net/anye3000/article/details/7941231
http://blog.sina.com.cn/s/blog_786ce14d01014ixq.html
4.10更新版本二:
#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 check( char op )
{
int value = -1;
switch(op)
{
case '(':
value = 0;
break;
case '+':
case '-':
value = 1;
break;
case '*':
case '/':
value = 2;
break;
}
return value;
}
int change( string str, char a[SIZE], int &len ,int &sum )
{
// 中缀式转换为后缀式
stack<char> oper;
oper.push('\0');
int i = 0;
int j = 0;
while( str[i] != '\0' )
{
if( str[i] >= '0' && str[i] <= '9' || str[i] == '.' )
{
a[j++] = str[i];
len++;
}
else if( str[i] == '(' )
{
oper.push(str[i]);
}
else if( str[i] == ')' )
{
while( oper.top() != '(' )
{
a[j++] = oper.top();
oper.pop();
len++;
}
oper.pop();
}
else if( i == 0 && (str[i] == '+' || str[i] == '-') && str[i+1] != 'a') //表明第一个数为正负号
{
a[j++] = str[i];
len++;
}
else if( i == 2 && (str[i] == '+' || str[i] == '-') && str[i-1] == 'a') //表明当出现"-a"时第三个数为正负号
{
a[j++] = str[i];
len++;
}
else if( i == 0 && str[i] == '-' && str[i+1] == 'a' /*&& str[i+2] == ' '*/ )
{
sum = 1;
}
else if( isOperator(str[i]) )
{
a[j++] = ' '; //用空格隔开数
len++;
while( check(str[i]) <= check( oper.top() ) )
{
a[j++] = oper.top();
oper.pop();
len++;
}
oper.push(str[i]);
}
i++;
}
while( oper.top() != '\0' )
{
a[j++] = oper.top();
oper.pop();
len++;
}
return 0;
}
double read(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 calculate( 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(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 str = "";
string str1 = "";
int i = 0;
int chang = 0;
char a[SIZE];
cin >> str;
chang = str.size();
int len = 0;
int sum = 0;
change( str, a, len ,sum);
a[len] = '\0';
if(sum == 1)
{
str1 = str.substr(2,chang-2);
cout << str1 << "= " << calculate(a) << endl;
}
else
cout << calculate(a) << endl;
system("pause");
return 0;
}
运行结果:
反思:
换了一种方案后能够实现输入“-a”时输出表达式,通过把中缀表达式转换成后缀表达式进行计算。但代码仍有很多细节不符合题目要求,需要进一步修改。