中缀表达式求值 ,中缀表达转化为后缀表达式求值,

中缀表达式求值

中缀表达式就是我们平常所见的数学式子   :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

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

.

   

原文地址:https://www.cnblogs.com/dchnzlh/p/9780044.html