題目鏈接:
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”時輸出表達式,通過把中綴表達式轉換成后綴表達式進行計算。但代碼仍有很多細節不符合題目要求,需要進一步修改。
