From 02ca72780298364ce1bf855375b46e66cd7b7d55 Mon Sep 17 00:00:00 2001 From: Shine wOng <1551885@tongji.edu.cn> Date: Wed, 22 May 2019 22:02:06 +0800 Subject: [PATCH] update computation of infix expression, tests passed. --- thu_dsa/chp4/stackApp.cpp | 143 +++++++++++++++++++++++++++++++--- thu_dsa/chp4/stackApp.h | 31 +++++++- thu_dsa/chp4/testStackApp.cpp | 9 ++- 3 files changed, 169 insertions(+), 14 deletions(-) diff --git a/thu_dsa/chp4/stackApp.cpp b/thu_dsa/chp4/stackApp.cpp index c892cea..1e4f669 100644 --- a/thu_dsa/chp4/stackApp.cpp +++ b/thu_dsa/chp4/stackApp.cpp @@ -1,11 +1,20 @@ #include "../chp2/Fib.h" #include "stackApp.h" +#include + +/*-----------build-in functions----------*/ +int readNumber(char* &expr); +int fac(int n); +inline char orderBetween(char optr1, char optr2); +int findOptr(char optr); +double cal(char optr, double opnd); +double cal(double opnd1, char optr, double opnd2); /* -* @brief : convert a decimal digit n to any base(2 <= base <= 36) -* @args : -* @return: return the result in the form of char* -*/ + * @brief : convert a decimal digit n to any base(2 <= base <= 36) + * @args : + * @return: return the result in the form of char* + */ char* convert(__int64 n, int base){ Stack charStack; while(n != 0){ @@ -20,13 +29,13 @@ char* convert(__int64 n, int base){ } /* -* @brief : to judge if an expression of matches -* @args : exp -* @return: return true if matches -*/ + * @brief : to judge if an expression of matches + * @args : exp + * @return: return true if matches + */ bool paren(const char exp[]){ Stack parenStack; - char currParen, popped; + char currParen; for(int ix = 0; (currParen = exp[ix]) != '\0'; ++ix){ switch(currParen){ case '(': @@ -53,3 +62,119 @@ bool paren(const char exp[]){ } return parenStack.empty()? true : false; } + +/* + * @brief : to compute the value of an infix expression + * @args : infixExpr + * @return: return the value in double + * @others: only consider valid infix expression + */ +double evaluate(char* infixExpr){ + Stack opnd; + Stack optr; + double opnd1, opnd2; + optr.push('\0'); + while(!optr.empty()){ + if (isdigit(*infixExpr)) opnd.push(readNumber(infixExpr)); + else{ + if (*infixExpr == ' ' || *infixExpr == '\t') { // skip white spaces + ++infixExpr; + continue; + } + + switch(orderBetween(optr.top(), *infixExpr)){ + case '>': + if (optr.top() == '!') opnd.push(cal(optr.pop(), opnd.pop())); + else{ + opnd2 = opnd.pop(); + opnd1 = opnd.pop(); + opnd.push(cal(opnd1, optr.pop(), opnd2)); + } + break; + + case '<': + optr.push(*infixExpr++); + break; + + case '=': + infixExpr++; + optr.pop(); + break; + } + } + } + return opnd.pop(); +} + +/*-----------build-in functions----------*/ +int readNumber(char* &expr){ + int res = 0; + while(isdigit(*expr)){ + res = res * 10 + *expr - '0'; + expr++; + } + return res; +} + +inline char orderBetween(char optr1, char optr2){ + return pri[findOptr(optr1)][findOptr(optr2)]; +} + +int findOptr(char optr){ + if (optr == '+') return 0; + if (optr == '-') return 1; + if (optr == '*') return 2; + if (optr == '/') return 3; + if (optr == '^') return 4; + if (optr == '!') return 5; + if (optr == '(') return 6; + if (optr == ')') return 7; + if (optr == '\0') return 8; +} + +int fac(int n){ + int res = 1; + for (; n != 0; res *= n, n--); + return res; +} + +double cal(char optr, double opnd){ + double res = 0.0; + switch(optr){ + case '!': + res = fac(opnd); + break; + default: + break; + } + return res; +} + +double cal(double opnd1, char optr, double opnd2) { + double res = 0.0; + switch (optr){ + case '+': + res = opnd1 + opnd2; + break; + + case '-': + res = opnd1 - opnd2; + break; + + case '*': + res = opnd1 * opnd2; + break; + + case '/': + res = opnd1 / opnd2; + break; + + case '^': + res = pow(opnd1, opnd2); + break; + + default: + break; + } + return res; +} diff --git a/thu_dsa/chp4/stackApp.h b/thu_dsa/chp4/stackApp.h index 427e644..5d44422 100644 --- a/thu_dsa/chp4/stackApp.h +++ b/thu_dsa/chp4/stackApp.h @@ -3,6 +3,8 @@ #include "Stack.h" +#define NOPTR 9 + static char digits[] = { '0','1','2','3','4','5','6','7','8','9', 'a','b','c','d','e','f','g','h','i','j', 'k','l','m','n','o','p','q','r','s','t', @@ -15,10 +17,31 @@ static char digits[] = { '0','1','2','3','4','5','6','7','8','9', char* convert(__int64 n, int base); /* -* @brief : to judge if an expression of parens matches -* @args : exp -* @return: return true if matches -*/ + * @brief : to judge if an expression of parens matches + * @args : exp + * @return: return true if matches + */ bool paren(const char exp[]); +//pri[stack top optr][curr optr] +const char pri[NOPTR][NOPTR] = { + /* + - * / ^ ! ( ) \0 */ + /* + */ '>', '>', '<', '<', '<', '<', '<', '>', '>', + /* - */ '>', '>', '<', '<', '<', '<', '<', '>', '>', + /* * */ '>', '>', '>', '>', '<', '<', '<', '>', '>', + /* / */ '>', '>', '>', '>', '<', '<', '<', '>', '>', + /* ^ */ '>', '>', '>', '>', '>', '<', '<', '>', '>', + /* ! */ '>', '>', '>', '>', '>', '>', '<', '>', '>', + /* ( */ '<', '<', '<', '<', '<', '<', '<', '=', ' ', + /* ) */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + /* \0 */ '<' ,'<', '<', '<', '<', '<', '<', ' ', '=' }; + +/* + * @brief : to compute the value of an infix expression + * @args : infixExpr + * @return: return the value in double + * @others: only consider valid infix expression + */ +double evaluate(char* infixExpr); + #endif diff --git a/thu_dsa/chp4/testStackApp.cpp b/thu_dsa/chp4/testStackApp.cpp index 55b8228..1f8f9ee 100644 --- a/thu_dsa/chp4/testStackApp.cpp +++ b/thu_dsa/chp4/testStackApp.cpp @@ -8,12 +8,14 @@ using std::endl; void test_convert(); void test_paren(); +void test_evaluate(); int main(){ cout << "Running tests......" << endl; test_convert(); test_paren(); - + test_evaluate(); + cout << "All tests passed." << endl; system("pause"); return 0; @@ -31,3 +33,8 @@ void test_paren(){ assert(paren("[(])") == false); assert(paren("{[()]{[({})]}}") == true); } + +void test_evaluate(){ + assert(evaluate("2*5+(3+4-2*7)/2") == 6.5); + assert(evaluate("(0!+ 1) * 2 ^ (3!+ 4) - (5!- 67 - (8 + 9))") == 2012); +}