题目大意: 四则运算,在考虑运算符优先级的情况下,去除多余的括号,然后保证计算后的结果与之前的一样。
解题思路,先转成后缀表达式去除括号,然后通过后缀表达式加必要的括号转成中缀表达式。
中缀转后缀:
从左到右扫描中缀表达式,
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';
}