数据结构之栈应用(中缀表达式转后缀表达式)
目录
代码实现
#include<iostream>
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
string infix,postfix;
typedef struct Node {
int data;
char str;
struct Node *next;
}*linkstack;
typedef struct Lkstack {
struct Node *top;
int length;
}*Lstack;
void initstack(Lstack s);//初始化栈
void Pushc(Lstack s,char e);//字符型数据入栈
void Popc(Lstack s,char *e);//字符型数据出栈
char Topc(Lstack s,char *e);//字符型栈顶元素
void Pushn(Lstack s,int e);//整形数据入栈
void Popn(Lstack s,int *e);//整形数据出栈
int Topn(Lstack s,int *e);//整形栈顶元素
int lenstack(Lstack s);//栈的长度
char visit(char e);//输出一位栈中元素
int stackTraverse(Lstack s);
int prio(char op);//运算符优先级排序
void Trans(string &str,string &str1,Lstack s);//中缀表达式转后缀表达式
void calculation(Lstack s,int *e);//计算后缀表达式
int main() {
int ans=0;
cout<<"输入四则表达式: ";
cin>>infix;
Lstack in=new Lkstack;
initstack(in);
Trans(infix,postfix,in);
cout<<"后缀表达式: "<<postfix<<endl;
calculation(in,&ans);
cout<<"计算结果: "<<ans;
return 0;
}
void initstack(Lstack s) {
s->top=NULL;
s->length=0;
return;
}
void Pushc(Lstack s,char e) {
linkstack l=new Node;
l->str=e;
l->next=s->top;
s->top=l;//将新的节点l赋给栈顶指针
s->length++;
return;
}
void Popc(Lstack s,char *e) {
if(s->length==0) return ;
*e=s->top->str;
s->top=s->top->next;
s->length--;
}
char Topc(Lstack s,char *e) {
*e=s->top->str;
return *e;
}
void Pushn(Lstack s,int e) {
linkstack l=new Node;
l->data=e;
l->next=s->top;
s->top=l;//将新的节点l赋给栈顶指针
s->length++;
return;
}
void Popn(Lstack s,int *e) {
if(s->length==0) return ;
*e=s->top->data;
s->top=s->top->next;
s->length--;
}
int Topn(Lstack s,int *e) {
*e=s->top->str;
return *e;
}
int lenstack(Lstack s) {
return s->length;
}
char visit(char e) {
cout << e << " ";
return true;
}
int stackTraverse(Lstack s) {
if (!lenstack(s)) {
cout << "链表为空!" << endl;
exit(0);
}
Lstack p;
p = s;
while (p->length) {
visit(p->top->str);
}
cout << endl;
return true;
}
int prio(char op) { //给运算符优先级排序
int priority;
if (op == '*' || op == '/')
priority = 2;
if (op == '+' || op == '-')
priority = 1;
if (op == '(')
priority = 0;
return priority;
}
void Trans(string &str,string &str1,Lstack s) { //引用传递
char c;
for (unsigned int i = 0; i<str.length() ; i++) {
if (str[i] >= '0' && str[i] <= '9') { //如果是数字,直接入栈
str1+=str[i];
} else { //否则不是数字
if(!lenstack(s)) //栈空则入站
Pushc(s,str[i]);
else if (str[i] == '(') //左括号入栈
Pushc(s,str[i]);
else if (str[i] == ')') { //如果是右括号,只要栈顶不是左括号,就弹出并输出
while(s->top->str!='(') {
str1+=Topc(s,&c);
Popc(s,&c);
}
Popc(s,&c); //弹出左括号,但不输出
} else {
while (prio(str[i]) <= prio(Topc(s,&c))) { //栈顶优先级大于等于当前运算符,则输出
str1+=c;
Popc(s,&c);
if (!lenstack(s)) //栈为空,停止
break;
}
Pushc(s,str[i]);//把当前运算符入栈
}
}
}
while (lenstack(s)) { //最后,如果栈不空,则弹出所有元素并输出
str1+=Topc(s,&c);
Popc(s,&c);
}
}
void calculation(Lstack s,int *e) {
int num=-1,a,b;
for(int i=0; postfix[i]!='\0'; i++) {
while(isdigit(postfix[i])) {
num=postfix[i]-48;
Pushn(s,num);
num=0;
i++;
}
switch(postfix[i]) {
case '+': {
Popn(s,&a);
Popn(s,&b);
Pushn(s,a+b);
break;
}
case '-': {
Popn(s,&a);
Popn(s,&b);
Pushn(s,b-a);
break;
}
case '*': {
Popn(s,&a);
Popn(s,&b);
Pushn(s,b*a);
break;
}
case '/': {
Popn(s,&a);
Popn(s,&b);
Pushn(s,b/a);
break;
}
}
}
Popn(s,e);
}
具体算法
- 中缀表达式转后缀表达式
(1)如果遇到操作数,我们就直接将其输出。
(2)如果遇到操作符,则将其放入到栈中,遇到左括号时也将其放入栈中。
(3)如果遇到一个右括号,则将栈元素弹出,弹出的操作符输出直到遇到左括号为止,但左括号只弹出并不输出。
(4)如果遇到任何其他的操作符,如**(“+”, “*”,“(”)**等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。只有在遇到" ) “的情况下才弹出” ( “,其他情况都不弹出” ( "。
(5)如果读到了输入的末尾,则将栈中所有元素依次弹出。
2. 后缀表达式运算
(1)将后缀表达式从左到右依次读取
(2)如果读到数字直接入栈
(3)如果读到运算符,则将栈顶的两个数字出栈,和此运算符做运算,再将计算的结果压入栈中。(先入栈的数为减数,后入栈的数为被减数 用top减或除top-1,得到的结果压入top-1中)
(4)重复上述步骤,最终的运算结果存在栈中。