poj 1400 Complicated Expressions去除多余的括号

题目大意: 四则运算,在考虑运算符优先级的情况下,去除多余的括号,然后保证计算后的结果与之前的一样。


解题思路,先转成后缀表达式去除括号,然后通过后缀表达式加必要的括号转成中缀表达式。

 

中缀转后缀:

从左到右扫描中缀表达式,

1.遇到操作数直接存入A.

2.遇到 ( 压入sptr栈

3.遇到+, -, 看sptr栈顶元素,若不为 ( ,则弹出存入A, 而后将当前操作符压入sptr.

4.遇到*, /, 看sptr栈顶的元素,仅仅当栈顶元素为 * 或 / 时 弹栈,存入A,再将遇到的操作符压栈sptr

5,遇到 ), 依次弹出sptr栈顶元素,直到弹出(为止。

若扫描完后,sptr还有元素,则依次弹出存入A.



后缀表达式转中缀表达式。

结果栈为A,操作符栈为sptr

对后缀表达式从后往前扫描

设置一个标志位isLeaf 表示当前处理的操作符是否是左子树,

初始化为false

1.如果当前为操作符


1.1 如果A栈顶操作符(说明在处理二叉树的左子树), 

如果A为空或栈顶不为操作, 符,则将当前操作符压入sptr


1.1如果isLeaf 为true(说明在处理的操作符作为父节点的左子树)

1.1.1如果A不为空且栈顶操作符为*或/, 当前操作符为+或-,则将)压入栈A, 将(压入sptr(为了标识左括号)

最后将当前操作符压入sptr. 然后将isLeaf设置为false,表示左子树的根节点处理完


1.2如果isLeaf 为false(说明在处理的操作符作为父节点的右子树),

如果sptr不为空,则比较当前操作符与sptr栈顶的操作符的优先级。

1.2.1如果sptr栈顶为 - , 若 当前操作符不为 * 和 / 时,将 ) 压入栈 A, 将 ( 压入 sptr

1.2.2如果sptr栈顶为 / , 将 ) 压入栈 A, 将 ( 压入sptr.

1.2.3如果sptr栈顶为 *, 当前操作符为+ 或 - 时, 将 ) 压入栈 A, 将 ( 压入sptr.

最后将当前操作符压入sptr.


2.如果当前为操作数

将操作数压入A.

然后进入如下判断:

2.1如果sptr为空,则结束

2.2如果sptr栈顶为( ,则将(压入A,转2.2继续判断,如果sptr为空结束, 如果不为@转2.3

2.3将sptr栈顶元素弹出,压入A, 将isLeaf设置为true,表示此运算符需要处理它的左子树.


最后将A逐个弹出,就是最终的结果

源码:

#include <cstdio>
#include <stack>
#include <cstring>

using namespace std;

const int maxn = 255;

char infix[maxn], postfix[maxn];
int n;

void infix2postfix(char *infix, char *postfix);//中缀转后缀 
void postfix2infix(char *infix, char *postfix);//后缀转中缀 
int compareOp(char op1, char op2); // 判断操作符优先级 
bool isOp(char op); //判断是否为运算符
 
int main()
{
	
	int n;
	scanf("%d", &n);
	while(n-- != 0)
	{
		char infix[maxn], postfix[maxn];
		scanf("%s", infix);
		infix2postfix(infix, postfix);
		postfix2infix(infix, postfix);
		printf("%s\n", infix);
	}

	return 0;
}

int compareOp(char op1, char op2)
{
	if(op1 == '*' || op1 == '/')
	{
		if(op2 == '*' || op2 == '/')
			return 0;
		else
			return 1;
	} 
	else
	{
		if(op2 == '+' || op2 == '-')
			return 0;
		else
			return -1;
	}
}

bool isOp(char op)
{
	return op == '-' || op == '+' || op == '*' || op == '/'; 
}
	 
void infix2postfix(char *infix, char *postfix)
{
	stack<char> sptr;
	for(char *letter = infix; *letter != '\0'; letter++) 
	{
		switch(*letter) 
		{
			case '(':
				sptr.push(*letter);
				break;
				
			case '+':
			case '-':
				while(!sptr.empty()) 
				{
					char tmp = sptr.top();
					if(tmp != '(' )
					{
						*postfix++ = tmp;
						sptr.pop();
					}
					else
						break;
				}
				sptr.push(*letter);
				break;
				
			case '*':
			case '/':
				while(!sptr.empty()) 
				{
					char tmp = sptr.top();
					if(tmp == '*' || tmp == '/')
					{
						*postfix++ = tmp;
						sptr.pop();
					}
					else
						break;
				}
				sptr.push(*letter);
				break;
			
			case ')':
				while(!sptr.empty()) 
				{
					 char tmp = sptr.top();
					 sptr.pop();
					 if(tmp != '(')
						*postfix++ = tmp;
					 else
					 	break;
				}
				break;
				
			default:
				*postfix++ = *letter;
				break;				
		}
	} 
	
	while(!sptr.empty()) 
	{
		*postfix++ = sptr.top();
		sptr.pop(); 
	} 
	*postfix = '\0';
} 


void postfix2infix(char *infix, char *postfix)
{
	stack<char>sptr;
	stack<char>A;
	int len = strlen(postfix);
	postfix += (len - 1); 
      bool isLeft = false;
	for(int i = 0; i < len; i++, postfix--) 
	{
		if(isOp(*postfix))
		{
			if(isLeft)
			{
				if(!A.empty() && (A.top() == '*' || A.top() == '/') && (*postfix == '+' || *postfix == '-'))
				{
					A.push(')');
					sptr.push('(');	
				}
				isLeft = false;			
			}
			else if(!sptr.empty())
			{
				if(sptr.top() == '-' && *postfix != '*' && *postfix != '/'
				|| sptr.top() == '/'
				|| sptr.top() == '*' && (*postfix == '+' || *postfix == '-') 
				   )
				{
					A.push(')');
					sptr.push('(');
				} 
			}
			sptr.push(*postfix);
		}
		else
		{
			A.push(*postfix);
			while(!sptr.empty() && sptr.top() == '(')
			{
				A.push(sptr.top());
				sptr.pop();
			}
			if(!sptr.empty())
			{
				A.push(sptr.top());
				sptr.pop();
                          isLeft = true;
			}
		}
	} 
	
	while(!A.empty())
	{
		*infix++ = A.top();
		A.pop();
	}
	*infix = '\0';
} 



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值