2015-10-18 10:42:52 +08:00

314 lines
8.4 KiB
C++

// Source : https://leetcode.com/problems/basic-calculator/
// Author : Hao Chen
// Date : 2015-06-12
/**********************************************************************************
*
* Implement a basic calculator to evaluate a simple expression string.
*
* The expression string may contain open ( and closing parentheses ), the plus + or minus sign -,
* non-negative integers and empty spaces .
*
* You may assume that the given expression is always valid.
*
* Some examples:
*
* "1 + 1" = 2
* " 2-1 + 2 " = 3
* "(1+(4+5+2)-3)+(6+8)" = 23
*
* Note: Do not use the eval built-in library function.
*
*
**********************************************************************************/
#include <stdlib.h>
#include <ctype.h>
#include <iostream>
#include <string>
#include <stack>
#include <vector>
using namespace std;
/*
* Sorry, I cannot help using Design Pattern ;-)
* (https://en.wikipedia.org/wiki/Interpreter_pattern)
*
* Two Stack is cheap, design pattern is powerful! ;-)
*
* But WTF, Memory Limit Exceeded!! Shit!!
*/
class Expression
{
public:
virtual int interpret() = 0;
virtual ~Expression() {};
};
class Number: public Expression
{
public:
Number(string num) { this->number = atoi(num.c_str()); }
~Number() { }
int interpret() { return number; }
private:
int number;
};
class Plus : public Expression
{
public:
Plus(Expression* left, Expression* right) :leftOperand(left), rightOperand(right) { }
~Plus() { delete leftOperand; delete rightOperand; }
int interpret() { return leftOperand->interpret() + rightOperand->interpret(); }
private:
Expression* leftOperand;
Expression* rightOperand;
};
class Minus : public Expression
{
public:
Minus(Expression* left, Expression* right) :leftOperand(left), rightOperand(right) { }
~Minus() { delete leftOperand; delete rightOperand; }
int interpret() { return leftOperand->interpret() - rightOperand->interpret(); }
private:
Expression* leftOperand;
Expression* rightOperand;
};
class Multiply : public Expression
{
public:
Multiply(Expression* left, Expression* right) :leftOperand(left), rightOperand(right) { }
~Multiply() { delete leftOperand; delete rightOperand; }
int interpret() { return leftOperand->interpret() * rightOperand->interpret(); }
private:
Expression* leftOperand;
Expression* rightOperand;
};
class Divide : public Expression
{
public:
Divide(Expression* left, Expression* right) :leftOperand(left), rightOperand(right) { }
~Divide() { delete leftOperand; delete rightOperand; }
int interpret() { return leftOperand->interpret() / rightOperand->interpret(); }
private:
Expression* leftOperand;
Expression* rightOperand;
};
bool isOperator(const string &c) {
return (c == "+" || c == "-" || c == "*" || c == "/" );
}
bool isOperator(const char &c) {
return (c == '+' || c == '-' || c == '*' || c == '/');
}
class Evaluator : public Expression
{
private:
Expression* syntaxTree;
public:
Evaluator(vector<string>& s)
{
vector<Expression*> stack;
for (unsigned int i=0; i < s.size(); i++) {
if (isOperator(s[i])) {
Expression* left = stack.back(); stack.pop_back();
Expression* right = stack.back(); stack.pop_back();
switch(s[i][0]) {
case '+' :
stack.push_back(new Plus(right, left)); break;
case '-' :
stack.push_back(new Minus(right, left)); break;
case '*' :
stack.push_back(new Multiply(right, left)); break;
case '/' :
stack.push_back(new Divide(right, left)); break;
}
}else{
stack.push_back(new Number(s[i]));
}
}
syntaxTree = stack.back();
}
~Evaluator() {
delete syntaxTree;
}
int interpret() {
return syntaxTree->interpret();
}
};
vector<string> Parse(string& s){
vector<string> exp;
for(int i=0; i<s.size(); ){
char c = s[i];
string token;
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' ) {
exp.push_back(token+c);
i++;
continue;
}
if ( isdigit(c) ) {
while( isdigit(s[i]) ) {
token.push_back(s[i++]);
}
exp.push_back(token);
continue;
}
i++;
}
return exp;
}
int Priority(const string &c) {
if (c == "*" || c == "/") {
return 2;
} else if (c== "+" || c == "-") {
return 1;
} else {
return 0;
}
}
vector<string> Infix2RPN(vector<string>& infix) {
vector<string> rpn;
stack<string> s;
for(int i = 0; i < infix.size(); i++) {
if(isdigit(infix[i][0])) { //number
rpn.push_back(infix[i]);
} else if (infix[i] == "(") {
s.push(infix[i]);
} else if (infix[i] == ")") {
while(!s.empty() && s.top() != "(") {
rpn.push_back(s.top());
s.pop();
}
s.pop();
}else if(isOperator(infix[i]) ){
while(!s.empty() && Priority(s.top()) >= Priority(infix[i])) {
rpn.push_back(s.top());
s.pop();
}
s.push(infix[i]);
}
}
while(!s.empty()) {
rpn.push_back(s.top());
s.pop();
}
return rpn;
}
//Design Pattern for RPN - Memory Limit Exceeded!!
int calculate_RPN_design_pattern(string& s) {
vector<string> exp = Parse(s);
//for (int i=0; i<exp.size(); i++){
// cout << exp[i] << " ";
//}
//cout << endl;
exp = Infix2RPN(exp);
for (int i=0; i<exp.size(); i++){
cout << exp[i] << " ";
}
cout << endl;
Evaluator sentence(exp);
return sentence.interpret();
}
/*
* RPN - Reverse Polish Notation
* see: https://en.wikipedia.org/wiki/Reverse_Polish_notation
*/
//RPN evluation - Memory Limit Exceeded!!
int calculate_RPN_evluation(string& s) {
vector<string> exp = Parse(s);
exp = Infix2RPN(exp);
stack<int> ss;
for(int i=0; i<exp.size(); i++) {
if (isdigit(exp[i][0])) {
ss.push(atoi(exp[i].c_str()));
}
if (exp[i]=="+" || exp[i]=="-") {
int rhs = ss.top(); ss.pop();
int lhs = ss.top(); ss.pop();
if (exp[i]=="-") rhs = -rhs;
ss.push(lhs + rhs);
}
}
return ss.top();
}
//Two stack solution - quick & dirty solution
inline void calculate_two_stacks(stack<int>& num_stack, stack<char>& op_stack) {
int lhs = num_stack.top(); num_stack.pop();
int rhs = num_stack.top(); num_stack.pop();
char op = op_stack.top(); op_stack.pop();
if (op=='-') rhs = -rhs;
num_stack.push(lhs + rhs);
}
int calculate_two_stacks(string& s) {
stack<int> num_stack; //put the number
stack<char> op_stack; //put the operations
for(int i = s.size() - 1; i >= 0; i--){
if(s[i] == ')' || s[i] == '+' || s[i] == '-') {
op_stack.push(s[i]);
} else if(isdigit(s[i])){
string num;
num += s[i];
while(isdigit(s[i-1])){
num.insert(num.begin(), s[i-1]);
i--;
}
num_stack.push(atoi(num.c_str()));
} else if(s[i] == '('){
while(op_stack.top() != ')') {
calculate_two_stacks(num_stack, op_stack);
}
op_stack.pop();
}
}
while(!op_stack.empty()){
calculate_two_stacks(num_stack, op_stack);
}
return num_stack.top();
}
int calculate(string s) {
return calculate_two_stacks(s);
return calculate_RPN_evluation(s);
return calculate_RPN_design_pattern(s);
}
int main(int argc, char** argv) {
string s = " 15-(1+3)+(2+1) ";
if (argc >1){
s = argv[1];
}
cout << s << " = " << calculate(s) << endl;
cout << "---------------" << endl;
s = "(2+4)-(6+(1+5))";
cout << s << " = " << calculate(s) << endl;
}