最开始做表达式求值的时候,思路不太清晰,后来想了想,有两种方式:方式一:先把中缀表达式转成后缀表达式,然后再求值就方便多了;方式二:算符优先方式。
发觉细节处理上很麻烦,最开始打算用C写,用自己的栈。后来发现自己的栈跟数据类型有密切联系,由于不能用模板,所以两个不同数据类型的栈操作要实现两次,最后想到了用void*指针指向实际的数据,用的时候再转换,感觉增加了复杂度,又降低了效率,所以直接用C++的stack。
另外一个问题就是输入方式,一种用getchar(),但识别的时候由于要超前读取一个字符,所以要设置缓冲区。另一种是直接读入一行字符串,缺点是受到了数组大小的限制。本次采用的是第二种。
在对字符的处理方式上,这里选用获取到相应运算数时,存入字符数组,然后转换成double型。另一种就是变读入边处理,直接返回double型。
整体思路如下:
1、设置两个栈,一个称作optr,用于寄存运算符,另一个称作opnd,用于寄存操作数或运算结果。
2、从str字符数组开始扫描,若是操作数则进opnd栈,若是运算符则和optr栈的栈顶运算符比较优先级后作相应操作。直到整个表达式求职完毕(optr和当前读入的字符均为'=')。
代码如下:
- #include <iostream>
- #include <stack>
- #include <cctype>
- using namespace std;
- #define MAXVAL 100 /* the max length of input string */
- #define NUMBER '0' /* mark for find a number */
- char getop(char s[], char str[])
- {
- char c;
- int i;
- static int j = 0;
- i = 0;
- while ((s[0] = c = str[j]) == ' ' || c == '/t')
- j++;
- s[1] = '/0';
- if (! isdigit(c) && c != '.') {
- j++;
- return c;
- }
- if (isdigit(c)) {
- while (isdigit(s[++i] = c = str[++j]))
- ;
- }
- if (c == '.') {
- while(isdigit(s[++i] = c = str[++j]))
- ;
- }
- s[i] = '/0';
- return NUMBER;
- }
- int index(char c)
- {
- int ret;
- switch (c) {
- case '+':
- ret = 0;
- break;
- case '-':
- ret = 1;
- break;
- case '*':
- ret = 2;
- break;
- case '/':
- ret = 3;
- break;
- case '(':
- ret = 4;
- break;
- case ')':
- ret = 5;
- break;
- case '=':
- ret = 6;
- break;
- default:
- break;
- }
- return ret;
- }
- char precede(char top, char c, char priority[][7])
- {
- int i = 0, j =0;
- i = index(top);
- j = index(c);
- return priority[i][j];
- }
- double operate(double a, char op, double b)
- {
- double ret = 0;
- switch (op) {
- case '+':
- ret = a + b;
- break;
- case '-':
- ret = a - b;
- break;
- case '*':
- ret = a * b;
- break;
- case '/':
- ret = a / b;
- break;
- default:
- break;
- }
- return ret;
- }
- double evaluate_expression(char *str, char priority[][7])
- {
- stack<double> opnd;
- stack<char> optr;
- char c, s[MAXVAL], op, ch;
- double a, b;
- optr.push('=');
- c = getop(s, str);
- while (c != '=' || optr.top() != '=') {
- if (c == NUMBER) {
- opnd.push(atof(s));
- c = getop(s, str);
- } else {
- switch (ch = precede(optr.top(), c, priority)) {
- case '<': /* the top element of stack optr has lower priority */
- optr.push(c);
- c = getop(s, str);
- break;
- case '=': /* get off '(' and get next character */
- optr.pop();
- c = getop(s, str);
- break;
- case '>': /* pop and push compute result */
- op = optr.top();
- optr.pop();
- b = opnd.top();
- opnd.pop();
- a = opnd.top();
- opnd.pop();
- opnd.push(operate(a, op, b));
- break;
- default:
- break;
- }
- }
- }
- return opnd.top();
- }
- int main()
- {
- char str[MAXVAL];
- char priority[7][7] = {
- // + - * / ( ) =
- '>', '>', '<', '<', '<', '>', '>', // +
- '>', '>', '<', '<', '<', '>', '>', // -
- '>', '>', '>', '>', '<', '>', '>', // *
- '>', '>', '>', '>', '<', '>', '>', // /
- '<', '<', '<', '<', '<', '=', ' ', // (
- '>', '>', '>', '>', ' ', '>', '>', // )
- '<', '<', '<', '<', '<', ' ', '=' // =
- };
- gets(str);
- double ret = evaluate_expression(str, priority);
- printf("%g/n", ret);
- return 0;
- }