[算法设计与分析]第三章练习题:删除多余括号

问题描述
  从键盘输入一个含有括号的四则运算表达式,要求去掉可能含有的多余的括号,结果要保持原表达式中变量和运算符的相对位置不变,且与原表达式等价,不要求化简。另外不考虑'+'  '-'用作正负号的情况,即输入表达式不会出现(+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;

}


猜你喜欢

转载自blog.csdn.net/Pecony/article/details/79768833