栈及其应用-中缀表达式转后缀表达式并用后缀表达式求值
一:栈的基本原理
栈是一种特殊的线性表,因为它对线性表中的元素做出了明确的要求:栈中的元素只能从线性表的一端进出,且要遵循“先入后出”的原则,即先进栈的元素后出栈。
基于栈结构的特点,在实际应用中,通常会对栈执行以下两种操作:
向栈中添加元素,此过程被称为“进栈”(PUSH、入栈或压栈);
从栈中提取出指定元素,此过程被称为“出栈”(POP、或弹栈);
进栈和出栈一般采用数组和栈顶指针来实现栈。
进栈(PUSH)算法:
①:若top>=n,则给出溢出信息,作出错处理(进栈前首先检查栈是否已满,满则溢出,不满则作②);
②:top++(栈指针加1,指向进栈地址);
③:s[top]=x,结束(x为新进栈的元素)
#define n 100
void push(int s[],int *top,int *x)
{
if(*top==n)printf(“overflow”);
else { (*top)++;s[*top]=*x; }
}
出栈(POP)算法:
(出栈前首先检查栈是否为空栈,空则下溢,不空则作②);
①:若top<=0,则给出下溢信息,作出错处理
②:y=s[top],(出栈前,将出栈元素赋值给y)
③:top–(栈指针减1,指向栈顶);
void push(int s[],int *top,int *y)
{
if(*top==0)printf(“underflow”);
else { *y=s[*top]; (*top)--; }
}
二:中缀表达式值(Expr.cpp)
【问题描述】
输入一个中缀表达式(由0-9组成的运算数、加+减-乘*除/四种运算符、左右小括号组成),把中缀表达式转换成后缀形式,再求出后缀表达式的值并输出。
注意:必须用栈操作,不能直接输出表达式的值。
【输入文件】Expr.in
输入文件的第一行为一个合法的表达式字符串。
【输出文件】Expr.out
输出文件有两行,第一行为转化为后缀表达式后的形式,第二行为表达式的计算结果。
【输入样例】
9+(3-1)*3+10/2
【输出样例】
9 3 1 – 3 * + 10 2 / +
20
算法分析:
我们平时所用的标准四则运算表达式,如“9+(3-1)×3+10÷2”叫做中缀表达式。因为所有的运算符号都在两数字中间,我们首先将此类的中缀表达式转化为后缀表达式。
如“9+(3-1)×3+10÷2”转化为后缀表达式为“9 3 1 – 3 * + 10 2 / +”,叫后缀的原因为所有的符号都是在要运算数字的后面出现,之所以要转化为后缀表达式,是因为计算器处理起来更为方便,后面会讲解到。
转化规则:
①遇到数字:直接输出
②遇到’(’:压栈
③遇到’)’:持续出栈,如果出栈的符号不是’('则输出,否则终止出栈。
④遇到符号则判断该符号与栈顶符号的运算优先级,如果栈顶符号的运算优先级高于或者等于当前符号的优先级,则将栈顶元素出栈并输出,直到栈顶符号优先级低于当前运算符的优先级或栈为空,再将符号入栈;如果栈顶符号的运算优先级低于当前符号的运算优先级,则将当前符号压栈。
⑤处理完字符串后将栈中剩余的符号全部输出。
转化后的后缀表达式没有了括号,计算机将中缀表达式转化为后缀表达式后按照规则可以非常方便快速地计算出结果
其规则为:
①从左到右遍历表达式的每个数字和符号
②遇到数字就进栈
③遇到符号就将处于栈顶的两个数字出栈,进行运算,运算结果进栈
④运行到最后,栈顶元素就是最终结果。
程序:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
using namespace std;
#define MAXN 100
char s[MAXN]; //输入的中缀表达式存储数组
char a[MAXN]; //后缀表达式存储数组
char houzhui_stack[MAXN]; //将中缀表达式转化为后缀表达式使用的栈
int houzhui_top = -1; //后缀表达式栈的栈顶指针
int calcu_stack[MAXN]; //表达式计算的栈
int calcu_top = -1; // 计算的栈顶指针
//入栈操作
template<class T>
void push(T qq[], int* top, T* x)
{
if (*top == MAXN)printf("overflow");
else {
(*top)++;
qq[*top] = *x;
}
}
//出栈操作
template<class T>
void pop(T qq[], int* top, T* y)
{
if (*top == -1)printf("underflow");
else {
*y = qq[*top]; qq[*top] = NULL; (*top)--;
}
}
int opr(char x) //赋予运算符优先级
{
if (x == '+' || x == '-')return 0;
if (x == '*' || x == '/')return 1;
return -1;
}
int main()
{
int j=0; //后缀表达式数组指针
cin >> s; //输入字符表达式
for (int i = 0; i < strlen(s); i++)//循环遍历
{
if ((s[i] >= '0' && s[i] <= '9')) //操作数判断
{
//操作数判断,将其放入后缀表达式字符数组,用空格将操作数分隔开
do{
a[j++] = s[i]; //将操作数存入后缀表达式数组中
cout << s[i]; //输出
i++;
} while (s[i] >= '0' && s[i] <= '9'); //循环判断
a[j++] = ' '; cout << " "; //后缀表达式数组内用空格隔开操作数
}
if (i < strlen(s))
{
if (houzhui_top == -1)push(houzhui_stack, &houzhui_top, &s[i]); //如果栈空,直接入栈
else if (s[i] == '(') push(houzhui_stack, &houzhui_top, &s[i]); //如果是左括号,直接入栈
else if (s[i] == ')') { //如果是右括号,持续出栈,直到遇到左括号
while (true) {
char tmp; //定义字符变量tmp存储出栈字符
pop(houzhui_stack, &houzhui_top, &tmp);
if (tmp != '(') { a[j++] = tmp; cout << tmp << " "; } //将出栈操作符保存在后缀表达式的存储数组内
else break; //遇到左括号, 结束本次操作
}
}
else if (houzhui_top != -1 && opr(houzhui_stack[houzhui_top]) >= opr(s[i]))//如果栈不为空且栈顶操作符优先级大于当前操作符
{
do{
char h;
pop(houzhui_stack, &houzhui_top, &h); //持续出栈
a[j++] = h; //将出栈操作符保存在后缀表达式的存储数组内
cout << h << " "; //输出
}while (houzhui_top != -1 && (opr(houzhui_stack[houzhui_top]) >= opr(s[i]))); //循环判断
push(houzhui_stack, &houzhui_top, &s[i]); //直到栈顶操作符优先级小于当前操作符,将该操作符入栈
}
else push(houzhui_stack, &houzhui_top, &s[i]);// 如果栈顶操作符优先级小于当前操作符,直接入栈
}
}
//最后全部出栈
while (houzhui_top != -1) { cout << houzhui_stack[houzhui_top] << " "; a[j++] = houzhui_stack[houzhui_top]; houzhui_top--; }
//换行
cout << endl;
//后缀表达式计算过程
//循环遍历
for (int i = 0; i < strlen(a); i++)
{
int m = 0; //将字符数字转换为整型数字
while (a[i] >= '0' && a[i] <= '9')
{
m =m* 10+ a[i]-'0';
i++;
if (a[i] == ' ') //遇到空格说明此次操作数读取完毕
{
push(calcu_stack, &calcu_top, &m); //入栈
}
}
if (a[i] == '+' || a[i] == '-' || a[i] == '*' || a[i] == '/')//如果a[i]是运算符
{
int num1, num2,result; //存储出栈数字和计算结果
pop(calcu_stack, &calcu_top, &num1);
pop(calcu_stack, &calcu_top, &num2);
switch (a[i]) //对运算符进行判断
{
case '+':
result = num2 + num1; //+
push(calcu_stack, &calcu_top, &result);//入栈
break;
case '-':
result = num2 - num1; //-
push(calcu_stack, &calcu_top, &result);//入栈
break;
case '*':
result = num2 * num1; //*
push(calcu_stack, &calcu_top, &result);//入栈
break;
case '/':
result = num2 / num1; // /
push(calcu_stack, &calcu_top, &result);//入栈
break;
}
}
}
int output; //存储最后的计算结果
pop(calcu_stack, &calcu_top, &output); //最后将栈顶元素出栈
cout << output; //输出计算结果
return 0;
}
}
运行结果: