数据结构-前、中、后缀表达式

介绍

中缀表达式,指的是我们日常运算中所用的、将运算符号写在要运算的数字中间、利用括号等进行辅助标明优先级的计算式。如(3+2)*9/(4-1)这种运算式。

而后缀表达式(又称为逆波兰表达式),则是将运算符置于要计算的数字之后的运算式(3 + 2后缀表示就是3 2 +),运算符作用于它前面的两位数字,计算式严格按照从左至右的顺序,不再借用括号表明优先级。相比于中缀表达式,后缀表达式是更方便于计算机求解的一种式子。

如例式可化为3 2 + 9 * 4 1 - /

计算

计算过程为:+作用于3,2,则原式=5 9 * 4 1 - /

*作用于5,9 ,原式=45 4 1 - /

-作用于4 1,原式=45 3 /

/作用于45 3,结果为15,答案与中缀表达式相同

这个计算过程,我们可以用栈来模拟实现

如洛谷P1449

对于字符串s,做以下处理:

当遍历时,遇到.时,将前面的字符串转换为数字压入栈中;

int a=0,b=0;//初始化,用于记录数字的值
	for (int i=0; i<s1.size(); i++) {
		if (s1[i]>='0'&&s1[i]<='9') {
			a=b*10+s1[i]-'0';
			b=a;
		} 
		else if(s1[i]=='.') {//说明完整数字结束
			s.push(a);//压入栈中
			a=0,b=0;
		}

遇到运算符号时,记录栈顶,将栈顶弹出,记录,弹出,这两个数字就是运算符作用的数字,再将计算结果压入栈中

else {
			int n=s.top();//记录、弹出栈顶
			s.pop();
			int m=s.top();//同上操作
			s.pop();
			if (s1[i]=='+') s.push(m+n);//将运算结果压入栈中
			else if(s1[i]=='-') s.push(m-n);//注意分辨减数与被减数
			else if(s1[i]=='*') s.push(m*n);
			else s.push(m/n);//注意分辨除数与被除数
		}

最后结果就是栈顶的值

完整代码

#include <bits/stdc++.h>
using namespace std;
int main() {
	stack<int> s;
	string s1;
	cin>>s1;
	int a=0,b=0;
	for (int i=0; i<s1.size(); i++) {
        //压入数字
		if (s1[i]>='0'&&s1[i]<='9') {
			a=b*10+s1[i]-'0';
			b=a;
		} 
		else if(s1[i]=='.') {
			s.push(a);
			a=0,b=0;
		}
		else if(s1[i]=='@') break;//判断结束
        //进行运算
		else {
			int n=s.top();
			s.pop();
			int m=s.top();
			s.pop();
			if (s1[i]=='+') s.push(m+n);
			else if(s1[i]=='-') s.push(m-n);
			else if(s1[i]=='*') s.push(m*n);
			else s.push(m/n);
		}
	}
	cout<<s.top();
	return 0;
}

前缀表达式(又称波兰表达式),指的是将运算符放在数字前、从右到左计算的一种表达式

如3+2 转换前缀则为+ 3 2

运算方法也正好与后缀相反,是从右到左将字符串压入栈中,其余操作参照后缀表达式

表达式的转换

对于中缀表达式转换为后缀(或前缀)表达式一般有这几种方法

手动转换

方式为:

1)将表达式按计算顺序用括号括起来  如例式变为(((3+2)*9)/(4-1))

2)将符号向后移出对应的括号,如(3+2)变为(3 2)+,移完去除括号,就是后缀表达式

前缀表达式则是向前移出对应括号

利用二叉树转换

中缀表达式其实就是二叉树中序遍历的结果,前缀就是同一棵二叉树前序遍历的结果,后缀则为后序遍历结果(前篇已介绍三种遍历方式)

利用栈转换

遇到数字则不入栈,遇运算符,优先级大于栈中符号才入栈中,否则弹出,直到栈内符号优先级小于于它或者为空或遇到括号

遇(无条件入栈,遇)则弹出所有符号直到遇到第一个(

图解模拟过程:

数字入队,优先级大于栈顶入栈

if (s[i]>='0'&&s[i]<='9') q.push_back(s[i]);//数字入队
		else if (s[i]=='('||s1.empty()||precedence(s[i])>precedence(s1.top())) s1.push(s[i]);

遇)时,符号出栈直到遇到(

else if(s[i]==')') {
			while(!s1.empty()&&s1.top()!='(') {
				q.push_back(s1.top());
				s1.pop();//弹出所有大于它的运算符入队中
			}
			s1.pop();//弹出括号
		}

/优先级等于*,将*弹出,/入栈

	//不满足大于栈顶符号时将栈内符号弹出
			while (!s1.empty()&&precedence(s1.top())>=precedence(s[i])&&s1.top()!='('){
				q.push_back(s1.top());//弹出的入队
				s1.pop();
			}
			s1.push(s[i]);

遇(将符号弹出

将剩余符号全部弹出

while(!s1.empty()){//将栈内符号都弹出
		q.push_back(s1.top());
		s1.pop();
	}

得到3 2 + 9 * 4 1 - /

栈外元素可以用另一个队接收,方便直接运算

#include <bits/stdc++.h>
using namespace std;
stack<char> s1;
deque<char> q;
int precedence(char op) {
    if (op=='+'||op=='-') {
        return 1;
    } else if (op=='*'||op=='/') {
        return 2;
    }
    return 0;
}
int main() {
	string s;
	cin>>s;
	for (int i=0; i<s.size(); i++) {
		if (s[i]>='0'&&s[i]<='9') q.push_back(s[i]);//数字入队
		else if (s[i]=='('||s1.empty()||precedence(s[i])>precedence(s1.top())) s1.push(s[i]);
		else if(s[i]==')') {
			while(!s1.empty()&&s1.top()!='(') {
				q.push_back(s1.top());
				s1.pop();//弹出所有大于它的运算符入队中
			}
			s1.pop();//弹出括号
		}
		else {
			//不满足大于栈顶符号时将栈内符号弹出
			while (!s1.empty()&&precedence(s1.top())>=precedence(s[i])&&s1.top()!='('){
				q.push_back(s1.top());//弹出的入队
				s1.pop();
			}
			s1.push(s[i]);
		}
	}
	while(!s1.empty()){//将栈内符号都弹出
		q.push_back(s1.top());
		s1.pop();
	}
	while(!q.empty()){
		cout<<q.front()<<" ";
		q.pop_front();//输出改变后的式子
	}
	return 0;
}

中缀转前缀时需要从后往前遍历,当符号优先级大于等于栈顶时入栈,括号的判断需要反着来,其余同上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值