逆波兰计算器(存疑)
2018-02-28 12:28
176 查看
摘自The C Programming Language
逆波兰表示法:①所有运算符都跟在操作数后面。
②不需要圆括号,只要知道每个运算符需要几个操作数。
如:中缀表达式:(1 - 2) * (4 + 5) ; 逆波兰表达式:1 2 - 4 5 + *
计算器程序的实现:每个操作数都被一次压入到栈中;当一个运算符到达时,从栈中弹出相应数目的操作数(对二元运算符来说是两个操作数),把该运算符作用于弹出的操作数,并把运算结果再压入栈中。
如:上例中。首先把1和2压入到栈中,再用两者之差-1取代它们;然后,将4和5压入到栈中,再用两者之和9取代它们。最后,从栈中取出栈顶的-1和9,并把它们的积-9压入到栈顶。到达输入行的末尾时,把栈顶的值弹出来并打印。
#include <stdio.h>
#include <stdlib.h> /* 为了使用atof函数 */
#define MAXOP 100 /* 操作数或运算符的最大长度 */
#define NUMBER '0' /* 标识找到一个数 */
int getop(char);
void push(double);
double pop(void);
int main()
{
int type;
double op2;
char s[MAXOP];
while((type = getop(s)) != EOF){
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.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;
}注意:+与*满足交换律,因此,操作数弹出次序无关紧要。但是,-与/两个运算符的左右操作数必须加以区分,为了保证正确的次序,引进临时变量op2;
#define MAXVAL 100 /* 栈al的最大深度 */
int sp = 0; /* 下一个空闲栈的位置 */
double val[MAXVAL]; /* 值栈 */
/* push函数:把f压入到值栈中 */
void push(double f)
{
if(sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full, can't push %g\n", f);
}
/* 弹出并返回栈顶的值 */
double pop(void)
{
if(sp > 0)
return val[--sp];
else{
printf("error: stack empty\n");
return 0.0;
}
}进栈和出栈的标准用法:*p++ = val; val = *--p;
#include <ctype.h>
int getch(void);
void ungetch(int);
/* getop函数:获取下一个运算符或数值操作数 */
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[++i] = c = getch())
;
if(c == '.') /* 收集小数部分 */
while(isdigit[++i] = c = getch())
;
s[i] = '\0'; /* 最后一个存入digit数组中的元素不是数字,所以用'\0'取代最后一个元素 */
if(c != EOF)
ungetch(c);
return NUMBER;
}
程序中经常会出现这样的情况:程序不能确定它读入的输入是否足够,除非能超前多读入一些输入。
例如:读入一些字符合成一个数字时,在看到第一个非数字字符之前,已经读入的数的完整性是不能确定的。
由于程序要超前读入一个字符,这样就导致最后有一个字符不属于当前所要读入的数。
所以我们需要“反读”不需要的字符,即每当程序多读入一个字符时,就把它压回到输入中。
我们编写一对互相协作的函数来模拟 反取字符 操作。getch函数用于读入下一个待处理的字符,ungetch函数用于把字符放回到输入中。这样,以后在调用getch函数时,在读入新的输入前先返回ungetch函数放回的那个字符。
①ungetch函数把要压回的字符放到一个共享缓冲区(字符数组)中,当该缓冲区不空时,getch函数就从缓冲区读取字符;当缓冲区为空时,getch函数就直接从输入中读字符。
②用一个下标变量来记住缓冲区中当前字符的位置。
逆波兰表示法:①所有运算符都跟在操作数后面。
②不需要圆括号,只要知道每个运算符需要几个操作数。
如:中缀表达式:(1 - 2) * (4 + 5) ; 逆波兰表达式:1 2 - 4 5 + *
计算器程序的实现:每个操作数都被一次压入到栈中;当一个运算符到达时,从栈中弹出相应数目的操作数(对二元运算符来说是两个操作数),把该运算符作用于弹出的操作数,并把运算结果再压入栈中。
如:上例中。首先把1和2压入到栈中,再用两者之差-1取代它们;然后,将4和5压入到栈中,再用两者之和9取代它们。最后,从栈中取出栈顶的-1和9,并把它们的积-9压入到栈顶。到达输入行的末尾时,把栈顶的值弹出来并打印。
#include <stdio.h>
#include <stdlib.h> /* 为了使用atof函数 */
#define MAXOP 100 /* 操作数或运算符的最大长度 */
#define NUMBER '0' /* 标识找到一个数 */
int getop(char);
void push(double);
double pop(void);
int main()
{
int type;
double op2;
char s[MAXOP];
while((type = getop(s)) != EOF){
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.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;
}注意:+与*满足交换律,因此,操作数弹出次序无关紧要。但是,-与/两个运算符的左右操作数必须加以区分,为了保证正确的次序,引进临时变量op2;
#define MAXVAL 100 /* 栈al的最大深度 */
int sp = 0; /* 下一个空闲栈的位置 */
double val[MAXVAL]; /* 值栈 */
/* push函数:把f压入到值栈中 */
void push(double f)
{
if(sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full, can't push %g\n", f);
}
/* 弹出并返回栈顶的值 */
double pop(void)
{
if(sp > 0)
return val[--sp];
else{
printf("error: stack empty\n");
return 0.0;
}
}进栈和出栈的标准用法:*p++ = val; val = *--p;
#include <ctype.h>
int getch(void);
void ungetch(int);
/* getop函数:获取下一个运算符或数值操作数 */
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[++i] = c = getch())
;
if(c == '.') /* 收集小数部分 */
while(isdigit[++i] = c = getch())
;
s[i] = '\0'; /* 最后一个存入digit数组中的元素不是数字,所以用'\0'取代最后一个元素 */
if(c != EOF)
ungetch(c);
return NUMBER;
}
程序中经常会出现这样的情况:程序不能确定它读入的输入是否足够,除非能超前多读入一些输入。
例如:读入一些字符合成一个数字时,在看到第一个非数字字符之前,已经读入的数的完整性是不能确定的。
由于程序要超前读入一个字符,这样就导致最后有一个字符不属于当前所要读入的数。
所以我们需要“反读”不需要的字符,即每当程序多读入一个字符时,就把它压回到输入中。
我们编写一对互相协作的函数来模拟 反取字符 操作。getch函数用于读入下一个待处理的字符,ungetch函数用于把字符放回到输入中。这样,以后在调用getch函数时,在读入新的输入前先返回ungetch函数放回的那个字符。
①ungetch函数把要压回的字符放到一个共享缓冲区(字符数组)中,当该缓冲区不空时,getch函数就从缓冲区读取字符;当缓冲区为空时,getch函数就直接从输入中读字符。
②用一个下标变量来记住缓冲区中当前字符的位置。
#define BUFSIZE 100 char buf[BUFSIZE]; /* 用于ungetch函数的缓冲区 */ int bufp = 0; /* buf中下一个空闲位置*/ /* 取一个字符(可能是压回的字符) */ 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; }
相关文章推荐
- 栈和队列5|逆波兰计算器 - 数据结构和算法27
- 栈_逆波兰表达式_计算器实现_Golang版本
- 计算器(逆波兰运算表达式)
- 基于逆波兰RPN算法的计算器实现
- HDU1237 简单的计算器 【堆】+【逆波兰式】
- c# 逆波兰式实现计算器
- 逆波兰式的学习、运用(附带C++写的一个整数的计算器)
- 逆波兰计算器
- 一个逆波兰表达式实现的四则混合运算计算器
- 栈的应用之简易逆波兰计算器
- 逆波兰计算器的C完整C代码(输入须为后缀表达式)
- 简单逆波兰计算器
- 数据结构(6)--逆波兰计算器的运用
- 利用栈实现计算器,先转换为逆波兰式之后运算
- 栈之逆波兰计算器
- 计算器 | 逆波兰表达式
- 波兰式计算器
- 分享一个Swift语言的逆波兰表达式计算器的实现
- 怎么实现Linux下的逆波兰计算器dc?
- 基于逆波兰表达式的计算器