首先,先来了解下什么是逆波兰表达式?逆波兰表达式又叫做后缀表达式,相当于二叉树中后根遍历。比如:计算(1-2)*(4+5)= -9,写成逆波兰表达式为1 2 - 4 5 + *。我们需要用一个栈来保存终端读入的字符(以空格为分界,输入EOF(ctrl + d)结束输入),当遇到数字时就入栈保存,当遇到运算符时,就连续取出两个栈顶的数字并进行运算,然后把运算结果压入栈中,再次从终端读入字符。当终端结束一个表达式的输入时(回车),程序会把当前标记的栈顶的值输出出来,作为表达式的结果。
下面,就让我们来实现逆波兰计算器,代码如下:
/* calc.h */
#ifndef _CALC_H
#define _CALC_H
#ifdef __cplusplus
extern "C"
{
#endif
#define NUMBER '0'
extern void push(double);
extern double pop(void);
extern int getop(char []);
extern int getch(void);
extern void ungetch(int);
}
#endif
/* main.cpp */
#include
#include
#include "calc.h"
#ifdef __cplusplus
extern "C"{
#define MAXTOP 100
/***** author: 王志平
****** date: 2015-9-6
****** name: main()函数
****** 功能:实现逆波兰计算器
比如: 123.5 + 4.7
逆波兰表达式为: 123.45 4.7 +
输入此表达式就可以得到结果:128.15
稍微复杂一点的:1 2 - 4 5 + *
结果为-9
******************************/
int main(void)
{
int type;
double op2;
char s[MAXTOP];
while ((type = getop(s)) != EOF)//输入按ctrl + c结束输入
{
switch (type)
{
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 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;
}
#endif
}
/* gettop.cpp */
#include
#include
#include "calc.h"
#ifdef __cplusplus
extern "C"
{
/***** author: 王志平
****** date: 2015-9-6
****** name: int getop(char s[])
****** 功能:取下一个运算符或者数值运算分量
比如逆波兰输入:1 2 - 4 5 + *
每个输入要以空格隔开,不能123.45+ 4.7会出错
******************************/
int getop(char s[])
{
int i,c;
//跳过空格和制表符
c = getch();
s[0] = c;
while (s[0] == ' ' || c == '\t')
{
c = getch();
s[0] = c;
}
s[1] = '\0';//空格分割的一类输入终止,比如1 2 +,三个字符以空格分割,处理单字符,在后面加上结束标志
if (!isdigit(c) && c != '.')//不是数字
{
return c;
}
i = 0;
if(isdigit(c))//搜集整数部分
{
c = getch();
++i;
s[i] = c;
while (isdigit(s[i]))
{
c = getch();
++i;
s[i] = c;
}
}
if (c == '.')//搜集小数部分
{
c = getch();
++i;
s[i] = c;
while (isdigit(s[i]))
{
c = getch();
++i;
s[i] = c;
}
}
s[i] = '\0';//数字搜集完毕
if (c != EOF)//提前读了一个字符,回退回去,比如: 123.45空格,此时把+回退
{
ungetch(c);
}
return NUMBER;
}
#endif
}
/* getch.cpp */
#include
#ifdef __cplusplus extern "C" { #define BUFSIZE 100 static char buf[BUFSIZE];//输入缓冲区,getchar()从终端读取字符 static int bufp = 0; /***** author: 王志平 ****** date: 2015-9-6 ****** name: int getch(void) ****** 功能:取一个字符(可能是退回的字符) ******************************/ int getch(void) { return (bufp > 0) ? buf[--bufp] : getchar(); } /***** author: 王志平 ****** date: 2015-9-6 ****** name: void ungetch(int c) ****** 功能:把字符退回到输入中 ******************************/ void ungetch(int c) { if (bufp >= BUFSIZE) { printf("ungetch: too many characters\n"); } else { buf[bufp++] = c; } } #endif } /* stack.cpp */ #include
#ifdef __cplusplus extern "C" { #define MAXVAL 100 static int sp = 0; static double val[MAXVAL]; //存储栈,栈顶元素即为最终结果 /***** author: 王志平 ****** date: 2015-9-6 ****** name: void push(double f) ****** 功能:把元素f下推到栈中 ******************************/ void push(double f) { if(sp < MAXVAL) { val[sp++] = f; } else { printf("error: stack full,can't push %g\n",f); } } /***** author: 王志平 ****** date: 2015-9-6 ****** name: double pop (void) ****** 功能:弹出并返回栈顶的值 ******************************/ double pop(void) { if (sp > 0) { return val[--sp]; } else { printf("error: stack empty.\n"); return 0.0; } } } #endif