通過入棧出棧實現數學表示式的計算
阿新 • • 發佈:2019-02-05
#include <iostream>
#include <stack>
#include <string>
#include <cstring>
using namespace std;
class Exp {
stack<char> ops; // 運算子棧
stack<double> ds; // 資料棧
double v, lh, rh; // 計算結果和臨時變數
char op; // 讀取運算子
public:
double calinput() { //讀取並計算表示式,直到結束為止
do {
readdata(); //讀取資料
skipspace(); //跳過空白
} while (readop()); //讀取運算子
calremain(); //處理棧中剩餘的運算子
return v;
}
//讀取資料
void readdata() {
while (!(cin >> v)) { //讀取資料失敗,應該是左括號
cin.clear();
cin >> op; //讀取必須是左括號
if (op != '(') {
throw string("在該出現數值的地方遇到了") + op;
}
ops.push(op);
}
ds.push(v);
}
//跳過空格
void skipspace() {
//cin.peek()檢視不取走
while (cin.peek() == ' ' || cin.peek() == '\t') {
cin.ignore();
}
}
//讀取運算子,可能遇到右括號')'或者換行符'\n'
bool readop() {
while ((op = cin.get()) == ')') {
while (ops.top() != '(') { //找棧裡左括號'('
rh = ds.top(); //從棧中取出右運算元
ds.pop();
lh = ds.top(); //從棧中取出左運算元
ds.pop();
ds.push(cal(lh, ops.top(), rh)); //取出運算子,計算左右運算元
ops.pop();
}
ops.pop(); //丟棄找到的左括號'('
}
if (op == '\n') {
return false;
}
if (strchr("+-*/", op) == NULL) { //無效運算子
throw string("無效運算子") + op;
}
while (!ops.empty() && ops.top() != '(' && !prior(op, ops.top())) {
rh = ds.top();
ds.pop();
lh = ds.top();
ds.pop();
ds.push(cal(lh, ops.top(), rh));
ops.pop();
}
ops.push(op);
return true;
}
void calremain() {
while (!ops.empty()) {
rh = ds.top();
ds.pop();
lh = ds.top();
ds.pop();
ds.push(cal(lh, ops.top(), rh));
ops.pop();
}
if (ds.size() != 1) {
throw string("無效的表示式");
}
v = ds.top();
ds.pop();
}
double cal(double lh, char op, double rh) {
return op == '+' ? lh + rh : op == '-' ? lh - rh :
op == '*' ? lh * rh : lh / rh;
}
bool prior(char o1, char o2) {
return (o1 != '+' && o1 != '-' && o2 != '*' && o2 != '/');
}
};
int main(int argc, char** argv) {
Exp e;
try {
cout << e.calinput() << endl;
} catch (const string& e) {
cout << e << endl;
}
return 0;
}