华为机试题50-四则运算

描述

输入一个表达式(用字符串表示),求这个表达式的值。

保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。

数据范围:表达式计算结果和过程中满足 ∣val∣≤1000 ,字符串长度满足 1≤n≤1000

输入描述:

输入一个算术表达式

输出描述:

得到计算结果

示例1

输入:

3+2*{1+2*[-4/(8-6)+7]}

输出:

25


我觉得这道题很难,涉及到的知识点有《数据结构》中栈在表达式求值中的应用。

解题思路:

我们平时见到的表达式求值,是中缀表达式,例如计算A+B= ;这种操作符都在两个操作数之间的表达式,也就是中缀表达式。然而计算机世界中,并不是根据中缀表达式求值,而是根据后缀或前缀表达式求值,我们知道中缀表达式求值,是因为我们知道运算的优先级,先括号,再乘除,后加减....,计算机却并不知道,于是有大佬发明了前缀和后缀表达式,计算机直接根据表达式就可以求解,并不涉及运算符的优先级(ps:其实如果要算的表达式很长很繁琐的话,我们用中缀表达式计算可能还没有用前缀和后缀表达式计算来的快)。

说了这么多,那什么是前缀和后缀表达式,举个例子,计算A+B,其后缀表达式就是AB+,而前缀表达式就是+AB,很容易理解。

上图的第一行是我们常见的中缀表达式,第二行就是转换得到的后缀表达式了,标的序号就是从左到右的运算顺序,后缀表达式的运算符也是以这个顺序出现的。

这是我们人工转换的后缀表达式,那计算机是怎么将中缀表达式转换成后缀表达式的?

中缀转后缀:

初始化一个栈,用于保存暂时还不能确定运算顺序的运算符。

从左到右处理各个元素,直到末尾。可能遇到三种情况:

        1.遇到操作数。直接加入后缀表达式。

        2.遇到界限符。遇到"("直接入栈;遇到")"则依次弹出栈内运算符并加入后缀表达式,直到弹出"("为止。注意"("不加入后缀表达式。

        3.遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符,加入后缀表达式,若碰到"("或栈空则停止。之后再把当前运算符入栈。

按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式。

由于运算符属于字符型,而操作数是绝对值不大于1000的整数类型,转换成后缀表达式的存放是个问题。笔者开辟了两个数组,分别用来存放操作符和操作数,比如“56+32”转换成后缀是“56 32+”,我将操作数放在整型数组num中,为{56,32,2000},这里不存在操作数的地方都填2000,因为题目要求运算结果和运算过程中的值的绝对值不大于1000,我们后期看到2000,就知道这个地方没有操作数,而操作符存储在字符数组o中{'!','!','+'},在没有操作符的地方全填'!'。

将中缀转成后缀后,就是利用后缀表达式进行运算从而求出结果了

利用后缀表达式求值

只需要遍历操作符数组,依次进行运算便可。

例如上式,先扫描到'+',然后从后往前遍历'+'位置之前的操作数,弹出最近的两个操作数进行相加即可,相加结果保存到原来A在的位置,同时令B=2000,表示这个位置不再是操作数,然后将用过的操作符'+'赋值为'!',表示这个位置不再是操作符,依次按照扫描到的操作符进行计算即可。

运算完成后,遍历操作数的数组,找出其中不等于2000的数,就是计算结果。

代码如下所示:

#include <stdio.h>
#define        N        1000
#define        MAX      2000
typedef struct operator
{
    char ope;        //操作符
    int pri;         //优先级
}operator;
int main()
{
    char str[N],o[N];
    operator temp[N];            //temp数组用来暂存操作符
    int num[N],t=0,j,cal[2];
    int i=0,pos=0,pri,flag=0,cnt=0;
    gets(str);
    while(str[i]!='\0')
    {
        if(str[i]=='['||str[i]=='{')
        {
            str[i]='(';
        }
        else if(str[i]==']'||str[i]=='}')
        {
            str[i]=')';
        }
        i++;
    }
    for(j=0;j<i;j++)
    {
        o[j]='!';            //先把操作符全都初始化为'!'
        num[j]=MAX;          //把操作数全部初始为不可能出现的最大值
    }
    //中缀表达式转成机算的后缀表达式
    i=0;
    while(str[i]!='\0')
    {
        if(str[i]>='0'&&str[i]<='9')
        {
            t*=10;
            t+=str[i]-'0';
            flag=1;
        }
        else if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/')
        {
            if(flag==1)
            {
                num[pos++]=t;
                t=0;flag=0;
            }
            if(str[i]=='*'||str[i]=='/')
            {
                pri=1;
            }
            else if(str[i]=='+'||str[i]=='-')
            {
                pri=0;
                if(str[i]=='-'&&str[i-1]=='(')
                {
                    num[pos++]=0;
                }
            }
            while(temp[cnt-1].pri>=pri&&temp[cnt-1].ope!='('&&cnt!=0)
            {
                o[pos++]=temp[cnt-1].ope;
                cnt--;
            }
            temp[cnt].ope=str[i];
            temp[cnt].pri=pri;
            cnt++;
        }
        else if(str[i]=='(')
        {
            temp[cnt++].ope=str[i];
        }
        else if(str[i]==')')
        {
            if(flag==1)
            {
                num[pos++]=t;
                t=0;flag=0;
            }
            while(temp[cnt-1].ope!='(')
            {
                o[pos++]=temp[cnt-1].ope;
                cnt--;
            }
            if(temp[cnt-1].ope=='(')
            {
                cnt--;
            }
        }
        i++;
    }
    if (flag==1)
    {
        num[pos++] = t;
    }
    while (cnt>0)
    {
        o[pos++]=temp[--cnt].ope;
    }
    
    
    //根据后缀表达式求出结果
    for(i=0;i<pos;i++)
    {
        if(o[i]!='!')
        {
            cal[0]=cal[1]=MAX;
            for(j=i-1;j>=0;j--)
            {
                if(num[j]!=MAX)
                {
                    if(cal[1]==MAX)
                    {
                        cal[1]=num[j]; 
                        num[j]=MAX;
                    }
                    else
                    {
                        cal[0]=num[j];
                        break;
                    }   
                }
            }
            if(o[i]=='+')
                num[j]=cal[0]+cal[1];
            else if(o[i]=='-')
                num[j]=cal[0]-cal[1];
            else if(o[i]=='*')
                num[j]=cal[0]*cal[1];
            else if(o[i]=='/')
                num[j]=cal[0]/cal[1];
        }
        o[i]='!';
    }
    for(i=0;i<pos;i++)
    {
        if(num[i]!=MAX)
        {
            printf("%d\n",num[i]);
            break;
        }
    }
    return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值