zoukankan      html  css  js  c++  java
  • 中缀表达式求值 ,中缀表达转化为后缀表达式求值,

    中缀表达式求值

    中缀表达式就是我们平常所见的数学式子   :5+3    6+5*8   -3*(1-9) 等等  

    这类表达式的特点就是运算符与操作数有特定的规则  如"+"    加数+加数 、 ‘-’    被减数 -减数 等等  一般来说运算符在操作数中间

    这类表达式我们可以直接计算 ,但计算机计算却有些麻烦了

    所以我们必须设计一个合适有效的算法来让计算机计算这些表达式

    一种方式是  运用两个栈 一个存储操作符称为OPTR_Stack  另一个存储操作数称为OPAN_Stack

    规则:

    依次读入 c

    1.c是操作数 则压入操作数栈.。

    2.若c是操作符且 是非‘)’和‘(’的操作符 ,将c与操作符栈中栈顶的操作符比较优先级

       (1)若优先级   栈顶 <=c  则将c压入运算符栈中。

       (2)若优先级   栈顶 >  c   则将栈顶运算符弹出 并将运算数栈 中弹出两个字符  计算并将结果压入运算符栈,直至遇到左括号或者遇到满足(1)条件  把c 压入运算符栈中。

    3.若是'(’  压入栈中。

    4. 若c是‘')' 则将运算符栈 中栈顶的操作符弹出,并将运算数栈 中弹出两个字符   计算并将结果压入运算符栈,直至遇到'(',将'('中栈中删除 开始读取下一字符。

    5.若到字符串结束 则将运算符栈顶的操作符弹出 ,并将运算数栈 中弹出两个字符   计算并将结果压入运算符栈,直至栈空

    原理就是如果这个操作符优先级低的话 先计算前面优先级高的 

    比如计算 6*5+3   当读入6 *5后 读入+ 必须要将前面运算符级别高的'*'计算得出6*5=30 才能将后面的30与3相加。

    代码如下

    /*
    中缀表达式求值
    */
    #include<stdio.h>
    #include<iostream>
    #include<string>
    #include<string.h>
    #include<algorithm>
    #include<stack>
    #define ERROR 0x7f7f7f7f
    using namespace std;
    const int maxn=1100;
    int Priority(char c)//运算符的优先级
    {
        if(c=='(')
            return 0;
        if(c=='+'||c=='-')
            return 1;
        return 2;
    }
    void Preprocess(char *str,const char *s)//预处理将字符串转化为正数加减乘除
    {
        int top=0;
        int len=strlen(s);
        for(int i=0; i<len; i++)
        {
            if(s[i]==' '||s[i]=='=')
                continue;
            if(s[i]=='-'&&(i==0||s[i-1]=='('))//将-8+10转化为 0-8+10
                str[top++]='0';
            if(s[i]=='('&&(s[i-1]>='0'&&s[i-1]<='9')&&i>=1)//对于8(6-10) 变为8*(6-10)
                str[top++]='*';
            str[top++]=s[i];
        }
        str[top]=0;
    }
    double calcu(double num1,double num2,char c)//计算
    {
        double res;
        switch(c)
        {
        case '+':
            res=num1+num2;
            break;
        case '-':
            res=num1-num2;
            break;
        case '*':
            res=num1*num2;
            break;
        case '/':
            res=num1/num2;
            break;
        }
        return res;
    }
    double GetMidExpreVal(const char *s)//将中缀表达式转化为后缀表达式
    {
        /*
        操作数直接加入表
        操作符 、
        if  '(' 加入栈
            ')' 取出直至'('
            运算符若优先级大加入  否则弹出
        */
        const char* user_read=s;
        stack<char>OPTR;//运算符
        stack<double>OPAN;
        while(*user_read!='')
        {
            if((*user_read<='9'&&*user_read>='0')||*user_read=='.')//运算数
            {
                double dble;
                dble=atof(user_read);
                while((*user_read<='9'&&*user_read>='0')||*user_read=='.')//将指针移动到第一个非数字位置
                {
                    user_read++;
                }
                OPAN.push(dble);
            }
            else if(*user_read=='(')
                OPTR.push(*user_read++);
            else if(*user_read==')')
            {
                while(OPTR.top()!='(')
                {
                    char now_optr;
                    double num1,num2;
                    now_optr=OPTR.top();
                    OPTR.pop();
                    num2=OPAN.top();
                    OPAN.pop();
                    num1=OPAN.top();
                    OPAN.pop();
                    OPAN.push(calcu(num1,num2,now_optr));
                    /*
                    每次弹出一个操作符  两个操作数 将结果压入栈中
                    */
                }
                OPTR.pop();
                user_read++;
            }
            else
            {
                if(OPTR.empty())//特判如果栈中没运算符就直接加入(看成左括号)
                {
                    OPTR.push(*user_read++);
                    continue;
                }
                char now_optr=OPTR.top();
                if(Priority(*user_read)>Priority(now_optr))
                    OPTR.push(*user_read++);
                else
                {
                    OPTR.pop();
                    double num1,num2;
                    num2=OPAN.top();
                    OPAN.pop();
                    num1=OPAN.top();
                    OPAN.pop();
                    OPAN.push(calcu(num1,num2,now_optr));
                }
            }
        }
        while(!OPTR.empty())
        {
            char now_optr;
            double num1,num2;
            now_optr=OPTR.top();
            OPTR.pop();
            num2=OPAN.top();
            OPAN.pop();
            num1=OPAN.top();
            OPAN.pop();
            OPAN.push(calcu(num1,num2,now_optr));
        }
        return OPAN.top();
    }
    int main()
    {
        int t;
        char s[maxn],str[maxn];
        scanf("%d",&t);
        while(t--)
        {
         scanf("%s",s);
         Preprocess(str,s);
         printf("%0.2lf
    ",GetMidExpreVal(str));
        }
    }

    另一种方式就是:将中缀表达式转化为前缀表达式或者后缀表达式 

    前缀表达式  运算符在操作数前面  6+5            前缀表达式为+ 6 5

    后缀表达式  运算符在操作数后面 3*5              后缀表达式    3 5 *

    转化成前缀 或者后缀表达式的方便之处就是不用考虑运算符的优先级问题 

    转化为后缀表达式的过程其实就是上面利用中缀表达式求值的过程 

    过程不在描述   可以戳这里

    代码:

    /*
    中缀表达式转换为后缀表达式
    */
    #include<stdio.h>
    #include<iostream>
    #include<string>
    #include<string.h>
    #include<algorithm>
    #include<stack>
    #define ERROR 0x7f7f7f7f
    using namespace std;
    const int maxn=1100;
    int Priority(char c)//运算符的优先级
    {
        if(c=='(')
            return 0;
        if(c=='+'||c=='-')
            return 1;
        return 2;
    }
    void Preprocess(char *str,const char *s)//预处理将字符串转化为正数加减乘除
    {
        int top=0;
        int len=strlen(s);
        for(int i=0; i<len; i++)
        {
            if(s[i]==' '||s[i]=='=')
                continue;
            if(s[i]=='-'&&(i==0||s[i-1]=='('))//将-8+10转化为 0-8+10
                str[top++]='0';
            if(s[i]=='('&&(s[i-1]>='0'&&s[i-1]<='9')&&i>=1)//对于8(6-10) 变为8*(6-10)
                str[top++]='*';
            str[top++]=s[i];
        }
        str[top]=0;
    }
    void Mid_toBehExpress(char *str,const char *s)//将中缀表达式转化为后缀表达式
    {
        /*
        操作数直接加入表
        操作符 、
        if  '(' 加入栈
            ')' 取出直至'('
            运算符若优先级大加入  否则弹出
        */
        const char* user_read=s;
        stack<char>OPTR;//运算符
        while(*user_read!='')
        {
            if((*user_read<='9'&&*user_read>='0')||*user_read=='.')//运算数
            {
                while((*user_read<='9'&&*user_read>='0')||*user_read=='.')//将指针移动到第一个非数字位置
                {
                    *str++=*user_read++;
                }
                *str++=' ';
            }
            else if(*user_read=='(')
                OPTR.push(*user_read++);
            else if(*user_read==')')
            {
                while(OPTR.top()!='(')
                {
                    *str++=OPTR.top();
                    *str++=' ';
                    OPTR.pop();
                }
                OPTR.pop();
                user_read++;
            }
            else
            {
                if(OPTR.empty())
                {
                    OPTR.push(*user_read++);
                    continue;
                }
                char now_optr=OPTR.top();
                if(Priority(*user_read)>Priority(now_optr))
                    OPTR.push(*user_read++);
                else
                {
                    OPTR.pop();
                    *str++=now_optr;
                    *str++=' ';
                }
            }
        }
        while(!OPTR.empty())
        {
            *str++=OPTR.top();
            OPTR.pop();
            *str++=' ';
        }
        *str='';
    }
    int main()
    {
        int t;
        char s[maxn],str[maxn];
        scanf("%d",&t);
        while(t--)
        {
         scanf("%s",s);
         Preprocess(str,s);
         Mid_toBehExpress(s,str);
         cout<<s<<"="<<endl;
        }
    }

    计算中缀表达式有一个细节是一个'-'   怎么判断出他是符号还是减号

    当时看了一个博客https://www.cnblogs.com/dolphin0520/p/3708602.html觉得很好 

    但是对于-(-8)这样的式子就处理不了  

    今天无意间用WIN10的计算器  突然发现 如果你输入-8 他会自动在前面加一个0 变为0-8

    这样就把负数转化为 两个正数的加减法了

    .

       

  • 相关阅读:
    STL中的stack(堆栈)
    单链表的创建与删除
    面试题四 从尾到头打印链表
    第 1 章 第 2 题 空间敏感排序问题 位向量实现( bitset位向量 )
    第 1 章 第 2 题 位向量的数组实现问题 位运算实现
    第 1 章 第 1 题 高级语言的排序问题 C++标准算法实现
    面试题三 替换空格
    面试题二 二维数组中的查找
    面试题一 赋值运算符函数
    不为客户连接创建子进程的并发回射服务器( poll实现 )
  • 原文地址:https://www.cnblogs.com/dchnzlh/p/9780044.html
Copyright © 2011-2022 走看看