逆波兰算法的表示:所有的运算符都跟在操作数的后面。
(1-2)*(4+5)表示为1 2 – 4 5 + *,
从左到右依次将操作数压入栈中,当运算符到达时,根据运算符从栈中取出相应数目的操作数,计算结果,并将结果压入栈中。例如:现将1,2压入栈中,接着遇到了+,是一个二元操作符,因此从栈中取出两个操作数,计算结果,并将结果-1压入栈中,接着讲4,5压入栈中,接着又遇到了*,也是一个二元操作符,于是从栈中取出两个操作数(也即5和4),将计算结果9压入栈中,紧接着又遇到了*,还是一个二元操作符,于是又从栈中取出两个操作数(也即9和-1),讲计算结果-9压入栈中。当到达输入行的结尾时,将栈顶的元素作为最终的结果输出。
C语言代码描述:
main.c
#include<stdio.h> #include<stdlib.h> //为了使用atof函数 #include "calc.h" #define MAXOP 100 //atof(char s[])函数用于将字符串s转化为相应的双精度浮点数,从前面的第一个数字字符开始 main(){ int type; double op2; char s[100]; while((type = getop(s)) != EOF) { //参数s中保存的是获取到的操作数 switch(type) { case NUMBER: //如果取出的字符是数字的话就放在值栈中 push(atof(s)); break; //如果取出的是运算符号,则进行相应的操作 case '+': push(pop() + pop()); printf("+"); break; case '*': push(pop() * pop()); break; case '-': //+和*操作满足交换律,所以操作数弹出的顺序不影响结果, op2 = pop(); //但是-和/操作操作数弹出的顺序将会影响结果,所以需要设置一个临时的变量暂存先弹出来的操作数 push(pop() - op2); break; case '/': op2 = pop(); if(op2 != 0.0) push(pop() / op2); else printf("error: zero divisor\n"); break; case '\n': printf("\t%.8g\n", pop()); break; //如果取出的既不是数字也不是运算符号,则提示输入错误 default : printf("error: unknown command %s\n", s); break; } } return 0; }
getop.c 获取下一个运算符或操作数,获取到的操作数放在字符数组s中,获取到的运算符直接返回
#include <stdio.h> #include <ctype.h> #include "calc.h" //getch()用于获取一个字符 int getop(char s[]) { int i, c; while((s[0] = c = getch()) == ' ' || c == '\t' ) //跳过空格和制表符 ; s[1] = '\0'; if(!isdigit(c) && c != '.') //取出的是字符,就返回这个字符 return c; i = 0; if(isdigit(c)) //将操作数的整数各位积累起来 while(isdigit(s[++i] = c = getch())) ; if(c == '.') //将操作数的小数部分各位积累起来 while(isdigit(s[++i] = c = getch())) ; s[i] = '\0'; //字符串结束 if(c != EOF) ungetch(c); return NUMBER; //用于标识操作数的各位字符已经收集起来了 }
stack.c 进行入栈、出栈操作(栈中保存的是操作数及运算结果)
#include <stdio.h> #include "calc.h" #define MAXVAL 100 int sp = 0; double val[MAXVAL]; //保存操作数和计算结果的值栈 //把f压入到值栈中 void push(double f) { if(sp < MAXVAL) { //printf("stack没有满"); val[sp++] = f; } else printf("error: stack full, can't push %g\n", f); } //弹出并返回栈顶的值 double pop(void) { //void表示没有参数,如果不写将关闭参数检查,相当于可以接受可变参数 if(sp > 0) return val[--sp]; else { printf("error: stack empty\n"); return 0.0; } }
getch.c 用于获取一个字符
#include <stdio.h>
#define BUFSIZE 100
char buf[BUFSIZE];
int bufp = 0;
//得到一个字符(可能是压回缓存的字符也可能是从屏幕输入的字符)
int getch(void) {
//缓存是空的话就从屏幕输入
return (bufp > 0) ? buf[--bufp] : getchar();
}
//把字符压回到缓存中
void ungetch(int c) {
if(bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
ungetch()方法的作用:在调用getch()方法获取一个字符的时候,需要多读取一位才能判断是否已经将一个操作数或运算符的所有字符读取完毕,也就是说最后读入的一个字符不是当前需要的,ungetch()方法用于将最后读入的字符放回到缓存中。
calc.h 在头文件中声明各个源文件中需要使用的方法
#define NUMBER '0' //函数的声明 void push(double); double pop(void); int getop(char[]); int getch(void); void ungetch(int);
输入数据的时候要按照逆波兰表示的方法输入。