十、从中缀向后缀转换表达式

十、从中缀向后缀转换表达式

题目描述

中缀表达式就是我们通常所书写的数学表达式,后缀表达式也称为逆波兰表达式,在编译程序对我们书写的程序中的表达式进行语法检查时,往往就可以通过逆波兰表达式进行。我们所要设计并实现的程序就是将中缀表示的算术表达式转换成后缀表示,例如,将中缀表达式

(A 一 (B*C 十 D) *E) / (F 十 G )

转换为后缀表示为:

ABC*D 十 E * 一 FG十/

**注意:**为了简化编程实现,假定变量名均为单个字母,运算符只有+,-,*,/ 和^(指数运算),可以处理圆括号(),并假定输入的算术表达式正确。

**要求:**使用栈数据结构实现 ,输入的中缀表达式以#号结束

输入

整数N。表示下面有N个中缀表达式
N个由单个字母、整数和运算符构成的表达式

输出

N个后缀表达式。

测试输入期待的输出时间限制内存限制额外进程
测试用例 11
(A-(B*C+D)*E)/(F+G)#
ABC*D+E*-FG+/1秒64M0
测试用例 22
a+b*c-d#
a-b*(c+d)#
abc*+d-
abcd+*-
1秒64M0

解题思路

后缀表达式中不含有括号,且后缀表达式中的操作数顺序和中缀表达式的操作数顺序完全相同,只是运算符的位置改变了。考虑用栈来实现,我们可以设置两个栈,一个 opt 栈用来存放运算符,一个 exp 栈用来存放最后的后缀表达式

在将中缀表达式转换为后缀的时候,遵循的原则是:

  • 从左到右依次扫描中缀表达式,如果读到的是操作数,直接存入 exp 栈
  • 如果读到的是运算符,则进行判断
    • 该运算符是 ’ ( ',则直接存入 opt 栈
    • 该运算符是 ’ ) ',则将 opt 栈中对应 ‘(’ 前的所有运算符出栈,存入 exp 栈(这一对括号就可以直接舍弃了)
  • 如果该运算符不是括号,则将该运算符和 opt 栈顶运算符做比较
    • 优先级大于或等于 opt 栈顶运算符,则直接存入 opt 栈
    • 优先级小于 opt 栈顶运算符,则让 opt 栈顶运算符出栈并存入 exp 栈中。如果此时新的栈顶运算符优先级大于等于该运算符,继续让栈顶运算符出栈存入exp栈。最后再将该运算符存入 opt 栈
  • 当扫描完成后,opt 栈中还有运算符,则将 opt 所有运算符出栈,存入 exp 栈中

符号的优先级定义如下:

  • ( 优先级为 1
  • +-优先级为 3
  • */优先级为 3
  • ^ 优先级为 7
  • ) 优先级为 9

对于 测试用例1 的转换过程如下:

扫描字符串opt栈exp栈
((
(A(A
(A-(-A
(A-((-(A
(A-(B(-(AB
(A-(B*(-(*AB
(A-(B*C(-(*ABC
(A-(B*C+(-(+ABC*
(A-(B*C+D(-(+ABC*D
(A-(B*C+D)(-ABC*D+
(A-(B*C+D)*(-*ABC*D+
(A-(B*C+D)*E(-*ABC*D+E
(A-(B*C+D)*E)ABC*D+E*-
(A-(B*C+D)*E)//ABC*D+E*-
(A-(B*C+D)*E)/(/(ABC*D+E*-
(A-(B*C+D)*E)/(F/(ABC*D+E*-F
(A-(B*C+D)*E)/(F+/(+ABC*D+E*-F
(A-(B*C+D)*E)/(F+G/(+ABC*D+E*-FG
(A-(B*C+D)*E)/(F+G)/ABC*D+E*-FG+
(A-(B*C+D)*E)/(F+G)#ABC*D+E*-FG+/

上机代码

懒得手写 C 的栈了,我就直接使用了 C ++ 封装好的栈

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
using namespace std;

bool JudgeOpt(char a, char b)
{
	//判断两个运算符优先级
	int value1 = 0, value2 = 0;
	switch(a)
	{
		case '(': value1 = 1;break;
		case '+': value1 = 3;break;
		case '-': value1 = 3;break;
		case '*': value1 = 5;break;
		case '/': value1 = 5;break;
		case '^': value1 = 7;break;
		case ')': value1 = 9;break;
	}
	switch(b)
	{
		case '(': value2 = 1;break;
		case '+': value2 = 3;break;
		case '-': value2 = 3;break;
		case '*': value2 = 5;break;
		case '/': value2 = 5;break;
		case '^': value2 = 7;break;
		case ')': value2 = 9;break;
	}
	//优先级a<b则false
	if(value1 - value2 < 0)
		return false;
	else
		return true;
}
int main()
{
	int n = 0;
	scanf("%d",&n);

	stack<char> opt,exp;

	while(n--)
	{
		//初始化两个栈
		while(!opt.empty())
			opt.pop();
		while(!exp.empty())
			exp.pop();

		char str[110];
		scanf("%s",str);
		char ch;	//用一个ch来表示str[i]
		
		//求字符串长度
		int len = 0;
		while(str[len]!='\0')
			len++;
		
		//扫描字符串
		for(int i = 0; i < len; i++)
		{
			ch = str[i];
			if(ch == '#')	//扫描完毕则退出
				break;
			//操作数直接压栈
			if((ch >= 'a'&& ch <= 'z') || (ch >= 'A'&& ch <= 'Z') || (ch >= '0'&& ch <= '9'))
				exp.push(ch);
			else	//判断括号
			{
				if(ch == '(')//左括号直接压栈
					opt.push(ch);
				else if(ch == ')')//右括号则取opt中对应的操作符存入exp中
				{
					while(opt.top()!='(')
					{
						exp.push(opt.top());
						opt.pop();
					}
					opt.pop();//舍弃栈顶的左括号
				}
				else	//判断运算符
				{
					if(opt.empty() || JudgeOpt(ch, opt.top()))//优先级大直接存入
					{
						opt.push(ch);
					}
					else	//优先级小,栈顶元素出栈
					{
						exp.push(opt.top());
						opt.pop();
						while(!opt.empty())//继续出栈
						{
							if(JudgeOpt(opt.top(), ch))
							{
								exp.push(opt.top());
								opt.pop();
							}
							else
								break;
						}
						opt.push(ch);//最后ch存入opt
					}
				}
			}

		}
		//将opt剩余运算符存入exp中
		while(!opt.empty())
		{
			exp.push(opt.top());
			opt.pop();
		}
		//取出exp的后缀表达式,逆序输出
		int num = 1;
		while(!exp.empty())
		{
			str[num++]=exp.top();
			exp.pop();
		}
		for(int i = num - 1; i > 0; i--)
		{
			printf("%c", str[i]);
		}
		printf("\n");
	}
	return 0;
}
  • 16
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值