1、前言
逆波兰表示法是波兰逻辑学家J・卢卡西维兹(J・ Lukasiewicz)于1929年首先提出的一种表达式的表示方法 。后来,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。
逆波兰表达式又叫做后缀表达式,是一种没有括号,并严格遵循“从左到右”运算的后缀式表达方法,如下表所示:
正常表达式 | 逆波兰表达式 |
---|---|
a+b | a b + |
a+(b-c) | a b c - + |
a+(b-c)*d | a d b c - * + |
a=1+3 | a = 1 3 |
a*(b+c)+d | a b c + * d + |
前缀表达式:前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前。比如:- × + 3 4 5 6
中缀表达式就是常见的运算表达式,如(3+4)×5-6
后缀表达式:运算符位于操作数之后,就是 3 4 + 5 × 6 -
逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式
优势:
它的优势在于只用两种简单操作,入栈和出栈就可以搞定任何普通表达式的运算。其运算方式如下:
如果当前字符为变量或者为数字,则压栈,如果是运算符,则将栈顶两个元素弹出作相应运算,结果再入栈,最后当表达式扫描完后,栈里的就是结果。
逆波兰表达式是比较适合计算机语言的一种表达式,不同于平时的我们的中缀表达式
2、通过逆波兰表达式计算结果
算法步骤
1.首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
2.读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
4.从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的 结束并将该数字串直接输出。
5.如果不是数字,该字符则是运算符,此时需比较优先关系。
具体做法是:将该字符与运算符栈顶的运算符的优先关系相比较。如果该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。若不是的话,则将栈顶的运算符从栈中弹出,直到栈项运算符的优先级低于当前运算符,将该字符入栈。
6.重复步骤1~2,直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
需要注意的是,重点不在写程序,重点在于这些个图是怎么出来的,这些也都是前人的总结啊,示例代码如下:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
//栈结构
typedef struct Stack
{
char *elem;
int top;
int size;
}Stack;
//初始化栈
void initStack(Stack *S)
{
S->elem=(char *)malloc(30*sizeof(char));
S->top=-1;
S->size=30;
}
//判断是否栈为空
int isEmpty(Stack *S)
{
if(S->top==-1)
return 1;
else
return 0;
}
//入栈
void push(Stack *S,char x)
{
if(S->top==S->size-1)
{
printf("Stack Overflow!\n");
return;
}
S->elem[++S->top]=x;
}
//出栈
char pop(Stack *S)
{
char x;
if(S->top==-1)
{
printf("Stack Empty!\n");
return 0;
}
x=S->elem[S->top--];
return x;
}
//取栈顶元素,但是不删除栈顶元素
char top(Stack *S)
{
char x;
if(S->top==-1)
{
printf("Stack Empty!\n");
return 0;
}
x=S->elem[S->top];
return x;
}
//判断当前运算符和栈顶的元素的优先级大小
int isBigger(char cur, char top)
{
if((cur=='*' || cur=='/') && (top=='+' || top=='-'))
return 1;
else if(top=='(')
return 1;
else
return 0;
}
//计算逆波兰表达式的值
void cal(char *buffer)
{
int stack[30];
int top=-1;
unsigned int i=0;
int j=0;
int a,b;
char * temp=(char *)malloc(10*sizeof(char));//存放运算分量的临时数组
memset(temp,0,10);
for(i;i<strlen(buffer);i++)
{
if(buffer[i]>='0' && buffer[i]<='9')
temp[j++]=buffer[i];
else if(buffer[i]=='&')
{
stack[++top]=atoi(temp);
j=0;
memset(temp,0,10);
}
else if(buffer[i]=='+')
{
a=stack[top--];
b=stack[top--];
stack[++top]=a+b;
}
else if(buffer[i]=='-')
{
a=stack[top--];
b=stack[top--];
stack[++top]=b-a;
}
else if(buffer[i]=='*')
{
a=stack[top--];
b=stack[top--];
stack[++top]=a*b;
}
else if(buffer[i]=='/')
{
a=stack[top--];
b=stack[top--];
stack[++top]=b/a;
}
}
printf("%d\n",stack[top]);
}
int main()
{
char ch;
char buffer[30];
int t=0;
int i=0;
Stack s;
FILE * fp;
initStack(&s);
fp=freopen("in.txt","r",stdin);
while(scanf("%c",&ch))
{
if(ch=='#')//若字符串扫描完毕
{
while(!isEmpty(&s) && top(&s)!='(')
buffer[t++]=pop(&s);
if(isEmpty(&s))
{
buffer[t]='\0';
printf("%s\n",buffer);
cal(buffer);
break;
}
else if(top(&s)=='(')
{
printf("0 wrong...\n");
break;
}
}
if(ch=='+' || ch=='-' || ch=='*' || ch=='/')//运算符
{
//buffer[t++]='&';
while( !isEmpty(&s) && !isBigger(ch,top(&s)))//当前运算符比栈顶元素的优先级小,并且栈不为空
{
buffer[t++]=pop(&s);
}
push(&s,ch);//栈为空,或者是当前运算符比栈顶元素的优先级大,则直接入栈
}
else if(ch=='(')//左括号则直接进栈
{
push(&s,ch);
}
else if(ch==')')//右括号
{
while(!isEmpty(&s) && top(&s)!='(')//当栈顶元素不为'(',并且栈不为空,则退栈输出
{
buffer[t++]=pop(&s);
}
if(top(&s)=='(')//如果栈顶元素为'(',则进栈
pop(&s);
else if(isEmpty(&s))//若栈为空,则输入的表达式有错
{
printf("1 wrong...\n");
break;
}
}
else if(ch>='0' && ch<='9')//输入的是运算分量
{
while(ch>='0' && ch<='9')
{
buffer[t++]=ch;
ch=fgetc(fp);
}
buffer[t++]='&';
fseek(fp,-1,1);
}
}
return 0;
}