栈应用:中缀表达式求值

后缀表达式求值比较简单,基本过程为:遇到数字则进栈,遇到运算符则出栈俩数字然后计算结果,再把结果入栈,过程比较简单,不再复习了,下面着重记录中缀表达式求值

中缀表达式求值可以先将中缀转后缀,再用后缀计算结果,但是,有点太麻烦,而另一种方式是利用两个栈直接求值,思想与上一个笔记中缀转后缀几乎一样,但稍有差别,中缀表达式求值基本过称为:

定义两个栈,stack1存储数字,stack2存储运算符,将字符串str元素一个个扫描,遇到数字型则进栈stack1,遇到运算符型,则要看看栈stack2栈顶元素运算符优先级是否比自己大或等于,如果真比自己大,那么那个运算符出栈,假设出栈是运算符a,那么此时从stack1中出栈两个数字b、c参与运算,把运算结果进栈stack1,此时此字符还不能进栈,如果栈顶优先级还比自己大或等于,那么那个栈顶运算符还要拿出来运算,直到有小于自己的自己才进栈;遇到‘(’直接进stack2,遇到’)’,则就要把这一对括号之间运算符都一个个拿出来运算,当str[i]读到’\0’那么扫描结束,结束后还要注意stack2里应该还有一个运算符,于是还要多加一步运算,最终stack1中剩一个数,那就是最后结果

实际上,以上都是基于每个数都是一位数组成的,即形如3*(2+4)-2而不是形如30*(20+44)-2,下面的程序也是基于一位数,但是一位数的程序编制好了后,只需要稍微调整读取字符就可以应用任意表达式了,为了深刻理解中缀表达式求值,这里不考虑多位数,只考虑能体现核心算法的一位数型

#include <stdio.h>
#include <stdlib.h>
float Cal(char a,float b,float c)//运算函数,a为运算符,b、c分别为两数
{
    switch(a)
    {
    case '+':
        return (b+c);
        break;
    case '-':
        return (b-c);
        break;
    case '*':
        return (b*c);
        break;
    case '/':
        return (1.0*b/c);
        break;
    }
}


int main(void)
{
    float stack1[200];//存放数字栈
    char stack2[100];//存放运算符栈
    int top1=-1,top2=-1;
    int i = 0;
    char str[200];
    char a;
    float b,c;


    FILE *fp=fopen("data.txt","r");//使用文件读表达式,省得每次测试都要输
    fscanf(fp,"%s",str);
    printf("%s\n",str);
    while(str[i] != '\0')//一个字符一个字符来
    {
        if(str[i] == '+' || str[i] == '-')//如果str[i]是加号或减号,那么栈顶运算符可以拿出来运算了
        {
            if(top2==-1)//若栈表示没有运算符,自己是第一个,故须运算符入栈2
            {
                stack2[++top2]=str[i];
            }
            else
            {
                while(stack2[top2] == '+' || stack2[top2] == '-' || stack2[top2] == '*' || stack2[top2] == '/')
                {
                    a=stack2[top2--];//取出一个数字
                    c=stack1[top1--];//再取出一个数字
                    b=stack1[top1--];//栈2顶运算符拿出来
                    stack1[++top1]=Cal(a,b,c);//运算结果要入栈1
                    printf("\n%f%c%f=%f\n",b,a,c,stack1[top1]);//输出中间运算过程
                }
                stack2[++top2]=str[i];//运算完了之后该运算符要入栈2
            }
        }

        else if(str[i] == '*' || str[i] == '/')//如果str[i]是乘号或除号,则只有栈顶也是乘除号时才需要计算
        {
            if(top2==-1)//同上
            {
                stack2[++top2]=str[i];
            }
            else
            {
                while(stack2[top2] == '*' || stack2[top2] == '/')
                {
                    a=stack2[top2--];//同上
                    c=stack1[top1--];//同上
                    b=stack1[top1--];//同上
                    stack1[++top1]=Cal(a,b,c);//同上
                    printf("\n%f%c%f=%f\n",b,a,c,stack1[top1]);//同上
                }
                stack2[++top2]=str[i];//同上
            }
        }

        else if(str[i] == '(')//如果str[i]是左括号则直接压入栈2
        {
            stack2[++top2]=str[i];
        }

        else if(str[i] == ')')//如果str[i]是右括号,则计算第一个左括号前的所有操作符,最后将此左括号直接弹出
        {
            while(stack2[top2] != '(')
            {
                a=stack2[top2--];
                c=stack1[top1--];
                b=stack1[top1--];
                stack1[++top1]=Cal(a,b,c);
                printf("\n%f%c%f=%f\n",b,a,c,stack1[top1]);
            }
            stack2[top2--];//弹出
        }

        else//如果str[i]不是操作符则直接进去
        {
            stack1[++top1]=str[i]-'0';//数字,转为整数
        }
        i++;
    }
    while(top2!=-1)//遍历后如果栈不为空,计算剩下操作符
    {
        a=stack2[top2--];
        c=stack1[top1--];
        b=stack1[top1--];
        stack1[++top1]=Cal(a,b,c);
        printf("\n%f%c%f=%f\n",b,a,c,stack1[top1]);
    }
    printf("\n结果:%f\n",stack1[top1]);
    return 0;
}

data.txt中数据:
3*(2+4)-2

相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页