#include <stdio.h>
#define MAX_LENG 100
double calc(char str[]);
void rpn(char str[], double rpn[]);
void split(char str[], double s[]);
int isDigit(char c);
int isOperator(char c);
double atof(char s[]);
double peek();
void push(double n);
double pop();
int compare(char c1, char c2);
int type(char c);
int main() {
double f = calc("3 * (8 + 3)");
printf("%.8g\n", f);
return f;
}
制作一个简单的有四则运算功能的函数 calc()。
形参为普通表达式,如 3+4*9
得到逆波兰表达式形式的数组 {
3,4,9,*,+}
while (得到数组的每个元素) {
if (是数字) {
将操作数存入栈中,如 {
3,4,9}
} else if (是运算符) {
弹出两个操作数,执行相应运算,结果存入栈中;
如 {
3, 36}、{
39}
} else {
报错,不支持的符号
}
}
输出栈顶元素
double calc(char str[]) {
double c, temp;
double rpn_expre[MAX_LENG];
rpn(str, rpn_expre);
for (int i = 0; rpn_expre[i] != '\0'; i++) {
c = rpn_expre[i];
if (c == '+') {
push(pop() + pop());
} else if (c == '-') {
temp = pop();
push(pop() - temp);
} else if (c == '*') {
push(pop() * pop());
} else if (c == '/') {
temp = pop();
if (temp == 0.0) {
printf("error: zero divisor\n");
} else {
push(pop() / temp);
}
} else if (c == '%') {
temp = pop();
if (temp == 0.0) {
printf("error: zero divisor\n");
} else {
push((int)pop() % (int)temp);
}
} else {
push(c);
}
}
return pop();
}
将普通表达式转为逆波兰表达式 rpn()。
当 + 是运算栈顶时,由于 * 比 + 的优先级更高,直接入栈。
3+4*9
运算符和操作数单独存储,{3, 4, 9}、{+, *}
随后取出运算栈顶元素,添加到操作栈顶:{3, 4, 9, *, +}
3*4+9
...
读取到 4,并存入:{3, 4},{*}
读取到 +,由于 + 不比栈顶元素优先级高,运算栈元素全部出栈,并存入操作数栈,{3, 4, *}。
+ 再存入运算栈:{+}
读取到 9,存入:{3, 4, *, 9}
读取完毕,运算栈元素全部出栈,并存入操作数栈,{3, 4, *, 9, +}
3-(4+9)
...
读取到 4,并存入:{3, 4},{-, (}
读取到 +,由于栈顶是 (,被括号包裹的优先运算,+ 入栈:{3, 4},{-, (, +}
读取到 9,{3, 4, 9},{-, (, +}
读取到 ),将栈中 ( 之上的元素全部出栈,存入操作数栈:{3, 4, 9, +},( 也出栈:{-}
读取完毕,运算栈元素全部出栈,存入操作数栈:{3, 4, 9, +, -}
将表达式 "3+4*9" 拆分成 {
3, '+', 4, '*', 9} 形式
while (得到数组中的每个元素) {
if (是数字) {
放入 double[] 中
} else if (是 ')') {
'(' 之上的元素出栈,存入 double[] 中,'(' 也出栈;
} else if (栈顶是 '(') {
当前运算符直接入栈;
} else if (当前运算符比栈顶元素优先级更高) {
当前运算符直接入栈;
} else {
'(' 之上的元素出栈,若栈中没有 '(',则所有元素出栈;
存入 double[] 中,当前运算符再存入;
}
}
运算栈元素全部出栈,存入 double[];
void rpn(char str[], double rpn[]) {
int i, j;
double s[MAX_LENG];
split(str, s);
for (i = j = 0; s[i] != '\0'; i++) {
if (isDigit(s[i])) {
rpn[j++] = s[i];
} else if (s[i] == ')') {
while (peek() !