问题描述
从键盘输入一个含有括号的四则运算表达式,要求去掉可能含有的多余的括号,结果要保持原表达式中变量和运算符的相对位置不变,且与原表达式等价,不要求化简。另外不考虑'+' '-'用作正负号的情况,即输入表达式不会出现(+a)或(-a)的情形。
输入格式
表达式字符串,长度不超过255, 并且不含空格字符。表达式中的所有变量都是单个小写的英文字母, 运算符只有加+减-乘*除/等运算符号。
输出格式
去掉多余括号后的表达式
样例输入
样例一:
a+(b+c)-d
样例二:
a+b/(c+d)
样例三:
(a*b)+c/d
样例四:
((a+b)*f)-(i/j)
样例输出
样例一:
a+b+c-d
样例二:
a+b/(c+d)
样例三:
a*b+c/d
样例四:
(a+b)*f-i/j
从键盘输入一个含有括号的四则运算表达式,要求去掉可能含有的多余的括号,结果要保持原表达式中变量和运算符的相对位置不变,且与原表达式等价,不要求化简。另外不考虑'+' '-'用作正负号的情况,即输入表达式不会出现(+a)或(-a)的情形。
输入格式
表达式字符串,长度不超过255, 并且不含空格字符。表达式中的所有变量都是单个小写的英文字母, 运算符只有加+减-乘*除/等运算符号。
输出格式
去掉多余括号后的表达式
样例输入
样例一:
a+(b+c)-d
样例二:
a+b/(c+d)
样例三:
(a*b)+c/d
样例四:
((a+b)*f)-(i/j)
样例输出
样例一:
a+b+c-d
样例二:
a+b/(c+d)
样例三:
a*b+c/d
样例四:
(a+b)*f-i/j
分析:
这道题找规律:无意要解决两个问题,一个是括号嵌套,一个是是否去括号。
是否去括号:以运算等级1为加减,2位乘除加减。括号内为1外1去括号,括号内为1外2不去括号,括号内为2外1去括号,括号内为2外2去括号。(注意,这里的内的符号不包括嵌套括号里面的符号)
括号嵌套:控制循环判断的下标。
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
char exp[100] = "(a*b)+c/d";//定义待处理的表达式
const int N = strlen(exp);//定义表达式的长度
const char DE = 'X';//若该括号需要删除则赋值为DE 注意一定是char类型的
void DeleteBracket(int k);
int Judge(int k);
int main ()
{
DeleteBracket(0);
for(int i = 0; i < N; i ++){
if(exp[i] != DE)
printf("%c", exp[i]);
}
return 0;
}
void DeleteBracket(int k)
{
for(int i = 0; i < N; i++)
{
if(exp[i] == '(')//返回右括号的有下标
i = Judge(i);//控制下标处理嵌套括号
//i是遇到的左括号的下标
}
}
int Judge(int k)//k是左括号的下标
{
int out = 0;
int in = 0;
int aspect = 1;
int re = 0;
int judge = 0;//标记记录最左边的内嵌括号做为返回
int i;//记录右括号的下标
for(i = k + 1; i < N && aspect > 0; i++)//退出的条件是表达式结束 或者完全退出括号
{
if(exp[i] == '(')//此时说明有两个左括号紧挨着
{
aspect++;//括号的层次数+1
if(judge == 0)
{
re = i - 1;//此时属于有内嵌括号的情况 因此返回内嵌括号的左括号-1 因为返回到Fun函数时for循环有自增操作 增加后的值为左括号的下标
judge = 1;
}
}
if(aspect == 1)//此时需要计算第一层括号内的运算等级
{
if(in == 0)
{
if(exp[i] == '+' || exp[i] == '-')//因为i=k+1 而k是左括号的下标 因此i是括号内的第一个元素
in = 1;//加减的优先级是1
else if(exp[i] == '*' || exp[i] == '/')
in = 2;
}
if(in == 1)
{
if(exp[i] == '*' || exp[i] == '/')
in = 2;
}
}
if(exp[i] == ')')
{
aspect--;//此时证明处理完一层括号 因此层次数-1 而后进入for循环的判断条件 表达式是否处理完毕或者括号处理完毕
}
}
i--;//for循环退出后 i是右括号的下标 将循环退出时多加的1减去
//此时k为左括号下标 i为右括号下标
if(k > 0)//此时证明左边有符号 因为表达式的下标从0开始 而k是左括号的下标 如果k>0则证明一定存在符号与左括号挨着
{//左括号左边一定是符号而不可能是数 因此可以直接用if-else语句判断
if(exp[k - 1] == '+' || exp[k - 1] == '-')
out = 1;
else
out = 2;
}
//判断out的运算等级是否要提高 i是右括号的下标
if(out == 0 || out == 1)
{
if(i + 1 < N)//判断右括号是否为表达式的结尾 如果不是 则右括号的右边一定是一个符号
{
if(exp[i + 1] == '+' || exp[i + 1] == '-')//与上面判断括号左侧的原理相同
out = 1;
else
out = 2;
}
}
//本算法中对括号的删除 是通过将该位置的元素赋予特殊值 在打印的时候加以区分 而没有真正的从数组中去除
if(in == 0)//括号内部无符号 为单个空括号的情况 2+5+()-2
{
exp[i] = DE;//当内部无符号的时候 该括号可以直接删除 ik分别为右括号的左括号的下标
exp[k] = DE;
}
else if(in == 1 && out == 1)
{
exp[i] = DE;//此时内外均为加减运算 因此可以直接将括号去除
exp[k] = DE;
return i + 1;//此时返回原右括号的下一个元素的下标 进行下一步的处理
}
else if(in == 2)
{
exp[i] = DE;//此时内为乘除运算 因此无论外部是什么均可以直接将括号去除
exp[k] = DE;
}
if(re == 0)//如果没内嵌括号返回右括号下标 如果有内嵌括号返回内嵌括号的左括号-1
//因为函数返回到Fun()的for语句会自增到左括号下标 继续下一步的处理
re = i;
return re;
}