Basic Calculator
一.题意描述
题目要求解析一个含有数字,加号减号和括号的表达式,并算出其值,不能使用eval库函数。
二.解题思路
将整个表达式以括号分隔开,在从左到右扫描的过程中使字符依次进栈。只要遇到右括号,就将该括号中的值计算出来,将原来括号中的内容出栈,计算出的结果进栈。
具体来讲,只要不是右括号就进栈,否则先将一个变量(括号内的值,程序中为temp2)置为零,每次弹出两个元素,若第二个为+(-),则将temp2加(减)上第一个元素,若为(,将temp2加上第一个元素,并将所得结果进栈。由于每出现一个右括号就进行一次操作,栈中根本不会出现右括号,故不会出现括号内还嵌套括号的情况。一致扫描到字符串末尾即可。
过程中有三点值得说明:
1.为了避免在去掉所有括号之后还要将余下的所有数相加(减)的步骤,在扫描开始前现将左括号压栈, 扫描完成后将一个右括号压栈。
2.由于栈中既会有字符(+-()),也会有数字,故将字符采用负整数的方式存储,即(:-1 ):-2 +:-3 -:-4,这样只需使用一个int型的栈就好了。
3.对于数字不止一位的情况,由于扫描是从高位开始,故采用“原数*10+下一位”的方法,只将最后结果压栈。
由于整个字符串只扫描一遍,故该算法的复杂度为O(n).
三.一个问题
通过的程序是使用stack类来实现的,原来准备用自己写的QStack类的,但由于测试用例中有的的字符串很长,开始时需要分配的内存很大(栈的深度至少要550),在测评系统中会导致奇怪的错误。当栈的大小为520时可以通过34/37个测试用例,而只是转为使用stack类就可以通过了。
下面是源代码:
QStack版:
#include <iostream> using namespace std; typedef struct { int* data; int to; }QStack;//在栈中-1,-2表示括号,-3,-4表示加减号 void Push(QStack* &q,int num) { q->data[q->to] = num; q->to++; } void init(QStack* &q) { q->to = 0; q->data = new int[600]; } int Pop(QStack* &q) { q->to--; return q->data[q->to]; } int Top(QStack* &q) { return q->data[q->to-1]; } class Solution { public: int calculate(string s) { int i; int temp; int temp2; int temp1; QStack *q = new QStack; init(q); Push(q,-1); for(i = 0;i <= s.length();i++) { if(i == s.length()) { temp2 = 0; while(1) { temp1 = Pop(q); temp = Pop(q); if(temp == -3) temp2 += temp1; else if(temp == -4) temp2 -= temp1; else { temp2+=temp1; Push(q,temp2); break; } } } else { if(s[i] == ' ' || s[i] == '"') continue; else if(s[i] == '(') Push(q,-1); else if(s[i] == '+') Push(q,-3); else if(s[i] == '-') Push(q,-4); else if(s[i] == ')') { temp2 = 0; while(1) { temp1 = Pop(q); temp = Pop(q); if(temp == -3) temp2 += temp1; else if(temp == -4) temp2 -= temp1; else { temp2+=temp1; Push(q,temp2); break; } } } else { if(Top(q) >= 0) { temp = Pop(q)*10 + s[i] - 48; Push(q,temp); } else Push(q,s[i]-48); } } } return Pop(q); } }; int main() { char temp[10000]; Solution calc; cin >> temp; string s(temp); cout << calc.calculate(s); }
内置stack版
#include <iostream> #include <stack>//在栈中-1,-2表示括号,-3,-4表示加减号 using namespace std; class Solution { public: int calculate(string s) { int i; int temp;//弹出的第二个数 int temp1;//弹出的第一个数 int temp2; stack<int> q; q.push(-1); for(i = 0;i <= s.length();i++) { //最后加一个右括号 if(i == s.length()) { temp2 = 0; while(1) { temp1 = q.top(); q.pop(); temp = q.top(); q.pop(); if(temp == -3) temp2 += temp1; else if(temp == -4) temp2 -= temp1; else { temp2+=temp1; q.push(temp2); break; } } } else { if(s[i] == ' ' || s[i] == '"') continue; else if(s[i] == '(') q.push(-1); else if(s[i] == '+') q.push(-3); else if(s[i] == '-') q.push(-4); else if(s[i] == ')') { temp2 = 0; while(1) { temp1 = q.top(); q.pop(); temp = q.top(); q.pop(); if(temp == -3) temp2 += temp1; else if(temp == -4) temp2 -= temp1; else { temp2+=temp1; q.push(temp2); break; } } } else//输入的是数字 { if(q.top() >= 0) { temp = q.top()*10 + s[i] - 48; q.pop(); q.push(temp); } else q.push(s[i]-48); } } } return q.top(); } }; int main() { char temp[10000]; Solution calc; cin >> temp; string s(temp); cout << calc.calculate(s); }