简单四则运算之逆波兰式解法小结(C)
简单四则运算之逆波兰式解法
前提:数字为单个0~9,只有四则运算符,不含括号优先级(数字和优先级均可拓展)
易错点
1. 字符串读取
不含空格:整行读取
开辟char数组,以字符串形式 %s 读取,以空白符为分割;
含有空格:单个字符逐个读取
开辟char字符, %c 读取;
【注意 %c 的读取不会跳过空格等空白符,对于以空格为间隔的输入,可在 %c 前面加空格处理。即 "(空格)%c" 】
2. 数字与运算符混合处理
单个字符判断是否为十进制数字(0~9): isdigit() 函数 (头文件<ctype.h>)
数字字符char转int计算:- ‘0’
int数字转字符char输出:+ ‘0’
precede函数检查优先级:注意优先级相等情况的考虑!
操作数读取时注意先后顺序,被除(减)数和除(减)数不要弄反了!!
知识考点归纳
一般的表达式计算采用的是中缀(操作数在操作符两边紧挨着),逆波兰式则采用的是后缀(操作符紧挨在两个操作数后面)。
注意从左到右依次运算这一默认优先级。
表达式读取核心逻辑:
- 创建rpn主栈存储逆波兰式,oprs临时栈存储运算符;
- 先读取起始的三个字符,数字入rpn,运算符入oprs;
- 此后必为一个运算符,一个数字交替出现。所以,新读取运算符先与top(oprs)比较,后者优先级大于等于前者均出栈入rpn,新运算符一直与oprs栈顶元素比较,直到运算符优先级比栈顶高或者栈空为止。
- 读取完全部输入后不要忘记检查oprs是否为空,不为空则全部出栈依次入栈rpn。
- 因为是栈结构,所以最后输出前一定要进行反转。
- 逆波兰式的的读取计算较简单一些:读取数字一直入临时栈(存储操作数),直到读取运算符,弹出栈顶的两个元素进行运算(注意两个数的顺序),结果再入栈,继续读取,直到最后剩一个数字即为最终运算结果。(注意数字和字符的转化)
代码(C,包括简单的栈实现)
//简单四则远算(不含括号,两级运算优先级)逆波兰式解法 #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define ERROR 0 #define OK 1 typedef struct Stack { char *data; int top_index, max_size; } Stack; void init(Stack *s, int size) { s->data = (char *)malloc(sizeof(char) * size); s->max_size = size; s->top_index = -1; return; } int push(Stack *s, int data) { if (s->top_index >= s->max_size - 1) { return ERROR; } s->top_index++; s->data[s->top_index] = data; return OK; } int top(Stack *s) { return s->data[s->top_index]; } int pop(Stack *s) { if (s->top_index < 0) { return ERROR; } s->top_index--; return OK; } int empty(Stack *s) { if (s->top_index < 0) { return 1; } else { return 0; } } void clear(Stack *s) { free(s->data); free(s); return; } int precede(char c1, char c2) { int score1, score2; if(c1 == '+' || c1 == '-') { score1 = 0; } else { score1 = 1; } if(c2 == '+' || c2 == '-') { score2 = 0; } else { score2 = 1; } return score1 >= score2; } Stack *reverse(Stack *s) { Stack *tmp = (Stack *)malloc(sizeof(Stack)); init(tmp, 20); while (!empty(s)) { push(tmp, top(s)); pop(s); } clear(s); return tmp; } void output(Stack *s) { for (int i = s->top_index; i > 0; --i) { printf("%c", s->data[i]); } printf("%c\n", s->data[0]); return; } void calculate(Stack *s, char op) { int a = top(s) - '0'; pop(s); int b = top(s) - '0'; pop(s); switch (op) { case '+' : push(s, (b + a) +'0'); break; case '-' : push(s, (b - a) + '0'); break; case '*' : push(s, (b * a) + '0'); break; case '/' : push(s, (b / a) + '0'); break; } } int calc(Stack *s) { Stack *tmp = (Stack *)malloc(sizeof(Stack)); init(tmp, 20); char data; while (!empty(s)) { data = top(s); pop(s); if (isdigit(data)) { push(tmp, data); } else { calculate(tmp, data); } } return top(tmp) - '0'; } int main() { Stack *rpn = (Stack *)malloc(sizeof(Stack)); init(rpn, 20); Stack *oprs = (Stack *)malloc(sizeof(Stack)); init(oprs, 20); char *tmp = (char *)malloc(sizeof(char) * 20); scanf("%s", tmp); int i = 0; push(rpn, tmp[i++]); push(oprs, tmp[i++]); push(rpn, tmp[i++]); while (tmp[i] != '\0') { while (!empty(oprs) && precede(top(oprs), tmp[i])) { push(rpn, top(oprs)); pop(oprs); } push(oprs, tmp[i++]); push(rpn, tmp[i++]); } while (!empty(oprs)) { push(rpn, top(oprs)); pop(oprs); } rpn = reverse(rpn); output(rpn); printf("%d", calc(rpn)); clear(oprs); clear(rpn); free(tmp); return 0; }
C++实现(包括Stack类)
#include <iostream> #include <cassert> #include <string> using std::cin; using std::cout; using std::endl; using std::string; template<typename Type> class Stack{ public: Stack(int new_size) { size = new_size; data = new Type[size]; top_index = -1; } ~Stack() { delete[] data; } bool push(const Type &val) { if (top_index + 1 >= size) { return false; } top_index++; data[top_index] = val; return true; } bool empty() { return top_index < 0; } Type top() { assert(top_index >= 0); return data[top_index]; } bool pop() { if (empty()) { return false; } top_index--; return true; } void output() { for (int i = top_index; i >= 0; i--) { i == top_index || putchar(' '); cout << data[i]; } cout << endl; return; } void reverse() { Type *old_data = data; data = new Type[size]; for (int i = 0; i <= top_index; i++) { data[i] = old_data[top_index - i]; } delete[] old_data; return; } private: Type *data; int top_index, size; }; bool precede(const char &a, const char &b) { if ((a == '+' || a == '-') && (b == '*' || b == '/')) { return false; } return true; } int calc(char op, int a, int b) { switch(op) { case '+': { return a + b; } break; case '-': { return b - a; } break; case '*': { return a * b; } break; case '/': { return b / a; } break; } } int compute(Stack<char> &s) { Stack<char> temp(20); int a, b; char op; while (!s.empty()) { if (isdigit(s.top())) { temp.push(s.top()); s.pop(); } else { op = s.top(); s.pop(); a = temp.top() - '0'; temp.pop(); b = temp.top() - '0'; temp.pop(); temp.push(calc(op, a, b) + '0'); } } return temp.top() - '0'; } int main() { string str; cin >> str; Stack<char> rpn(20); Stack<char> opr(20); for (int i = 0; i < str.length(); i++) { if (isdigit(str[i])) { rpn.push(str[i]); } else { while (!opr.empty() && precede(opr.top(), str[i])) { rpn.push(opr.top()); opr.pop(); } opr.push(str[i]); } } while (!opr.empty()) { rpn.push(opr.top()); opr.pop(); } rpn.reverse(); cout << compute(rpn); }
易错用例1:
1+4/2+1
1 4 2 / + 1 + a = 4, b = 2, op = / a = 2, b = 1, op = + a = 3, b = 1, op = + 4
易错用例2:
1*2+3*4
1 2 * 3 4 * + a = 1, b = 2, op = * a = 2, b = 4, op = * a = 8, b = 3, op = + 11
Min是清明的茗