-
逆波兰表达式
逆波兰表达式又叫做后缀。在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法,按此方法,每一运算符都置于其运算对象之后,故称为后缀表示。
表达式
逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。逆波兰表达式又叫做后缀表达式。这个知识点在数据结构和编译原理这两门课程中都有介绍,下面是一些例子:
正常的表达式 逆波兰表达式
a+b ---> a,b,+
a+(b-c) ---> a,b,c,-,+
a+(b-c)*d ---> a,b,c,-,d,*,+
a+d*(b-c)--->a,d,b,c,-,*,+
a=1+3 ---> a=1,3 +
用途
逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。例如(a+b)*(c+d)转换为ab+cd+*
优势
它的优势在于只用两种简单操作,入栈和出栈就可以搞定任何普通表达式的运算。其运算方式如下:
如果当前字符为变量或者为数字,则压栈,如果是运算符,则将栈顶两个元素弹出作相应运算,结果再入栈,最后当表达式扫描完后,栈里的就是结果。
代码如下:
// 逆波兰式计算器
#include<iostream>
#include<string.h>
#include<ctype.h>
using namespace std;
#define LEN 100
// 定义栈结构体
typedef struct _Stack
{
double data; // 数据域
struct _Stack*next; // 指针域
}*MyStack,Node;
// 数据压栈
void Push(MyStack *s,double val)
{
MyStack pNew = new Node;
if (NULL==pNew)
{
cout << "动态申请内存失败!" << endl;
}
pNew->data = val;
pNew->next = NULL;
pNew->next = *s;
*s = pNew;
}
// 数据出栈
void Pop(MyStack *s,double *e)
{
if (*s==NULL)
{
cout << "栈已空" << endl;
exit(0);
}
*e = (*s)->data;
MyStack nPos = (*s);
*s = nPos->next;
delete nPos;
nPos = NULL;
}
// 销毁栈
void DestoryStack(MyStack *s)
{
MyStack nPos = *s;
while (nPos!=NULL)
{
MyStack temp = nPos;
nPos = temp->next;
delete temp;
temp = NULL;
}
}
// 显示栈中的数据
void Show(MyStack s)
{
while (s!=NULL)
{
double e = 0;
Pop(&s,&e);
cout << e << endl;
}
}
// 计算器处理函数
void Calc(void)
{
MyStack s = NULL;
char Operator[LEN] = "";
char c;
double a, b;
cout << "请输入逆波兰表达式,数字以空格结束,输入以'#'结束:" << endl;
c = getchar();
while (c != '#') // 输入以#结束
{
int i = 0;
// 输入数据并对数据进行压栈
while (isdigit(c) || c == '.')
{
Operator[i++] = c;
Operator[i] = '\0';
if (i >= 10)
{
cout << "输入的单个数据太大!" << endl;
return ;
}
c = getchar();
if (c == ' ')
{
double t = atof(Operator);
Push(&s, t);
i = 0;
memset(Operator,0,strlen(Operator));
}
}
// 进行操作符匹配
switch (c)
{
case '+':
Pop(&s,&a);
Pop(&s, &b);
Push(&s,a+b);
break;
case '-':
Pop(&s, &a);
Pop(&s, &b);
Push(&s, b-a);
break;
case '*':
Pop(&s, &a);
Pop(&s, &b);
Push(&s, a * b);
break;
case '/':
Pop(&s, &a);
Pop(&s, &b);
if (b==0)
{
cout << "除数不能为零!" << endl;
return;
}
else
Push(&s, b/ a);
break;
default:
break;
}
c = getchar();
}
cout << "计算结果是:" << endl;
Pop(&s, &a);
cout << a << endl;
}
int main(void)
{
Calc();
return 0;
}
// 例如计算 5-(6+7)*8+9/4
// 逆波兰表达式 5 6 7 + 8 * - 9 4 / + #
代码如下:
// 逆波兰式计算器
#include<iostream>
#include<string.h>
#include<ctype.h>
using namespace std;
#define LEN 100
// 定义栈结构体
typedef struct _Stack
{
double data; // 数据域
struct _Stack*next; // 指针域
}*MyStack,Node;
// 数据压栈
void Push(MyStack *s,double val)
{
MyStack pNew = new Node;
if (NULL==pNew)
{
cout << "动态申请内存失败!" << endl;
}
pNew->data = val;
pNew->next = NULL;
pNew->next = *s;
*s = pNew;
}
// 数据出栈
void Pop(MyStack *s,double *e)
{
if (*s==NULL)
{
cout << "栈已空" << endl;
exit(0);
}
*e = (*s)->data;
MyStack nPos = (*s);
*s = nPos->next;
delete nPos;
nPos = NULL;
}
// 销毁栈
void DestoryStack(MyStack *s)
{
MyStack nPos = *s;
while (nPos!=NULL)
{
MyStack temp = nPos;
nPos = temp->next;
delete temp;
temp = NULL;
}
}
// 显示栈中的数据
void Show(MyStack s)
{
while (s!=NULL)
{
double e = 0;
Pop(&s,&e);
cout << e << endl;
}
}
// 计算器处理函数
void Calc(void)
{
MyStack s = NULL;
char Operator[LEN] = "";
char c;
double a, b;
cout << "请输入逆波兰表达式,数字以空格结束,输入以'#'结束:" << endl;
c = getchar();
while (c != '#') // 输入以#结束
{
int i = 0;
// 输入数据并对数据进行压栈
while (isdigit(c) || c == '.')
{
Operator[i++] = c;
Operator[i] = '\0';
if (i >= 10)
{
cout << "输入的单个数据太大!" << endl;
return ;
}
c = getchar();
if (c == ' ')
{
double t = atof(Operator);
Push(&s, t);
i = 0;
memset(Operator,0,strlen(Operator));
}
}
// 进行操作符匹配
switch (c)
{
case '+':
Pop(&s,&a);
Pop(&s, &b);
Push(&s,a+b);
break;
case '-':
Pop(&s, &a);
Pop(&s, &b);
Push(&s, b-a);
break;
case '*':
Pop(&s, &a);
Pop(&s, &b);
Push(&s, a * b);
break;
case '/':
Pop(&s, &a);
Pop(&s, &b);
if (b==0)
{
cout << "除数不能为零!" << endl;
return;
}
else
Push(&s, b/ a);
break;
default:
break;
}
c = getchar();
}
cout << "计算结果是:" << endl;
Pop(&s, &a);
cout << a << endl;
}
int main(void)
{
Calc();
return 0;
}
// 例如计算 5-(6+7)*8+9/4
// 逆波兰表达式 5 6 7 + 8 * - 9 4 / + #