适用于实数范围的中缀表达式的 + - * / ( ) 计算(C++实现)

核心算法:

mid=FormatMid(mid);   //格式化中缀表达式
JudgeLegalMid(mid);  //判断中缀表达式的合法性
MidToPost mtp(mid);
mtp.ToPost(post);  //中缀表达式转后缀表达式
cout <<"结果:" <<Calc(post) <<endl;  //计算后缀表达式

具体过程——

第一步:格式化中缀表达式

  这一步的目的是为了解决“-”的歧义问题:有时候“-”是一元运算符,有时候“-”是二元运算符。可以用一种巧妙的方案解决歧义——在一元运算符的“-”前面添上0。这样,此后就可以把+-*/统一当做二元运算符处理。

具体代码:(放在FormatMid.h文件中)

#include<string>
#include<vector>
#include<iostream>
using namespace std;

string FormatMid(string mid)
{
    for (int i=0;i<mid.length();i++)
    {
        if (mid[i]==‘-‘ && (i==0||mid[i-1]==‘(‘))
        {
            mid.insert(i,"0");
            i++;
        }
    }
    string realmid="";
    for (int i=0;i<mid.length();i++)
    {
        if (mid[i]!=‘-‘)
        {
            realmid+=mid[i];
        }
        else
        {
            int cou=0;
            while (mid[i]==‘-‘) i++,cou++;
            if (cou%2==0) realmid+=‘+‘;
            else realmid+=‘-‘;
            i--;
        }
    }
    return realmid;
}

第二步:判断中缀表达式的合法性

  这一步也是为了程序的鲁棒性,具体代码如下:(放在JudgeLegalMid.h文件中)

#include<iostream>
#include<cstring>
#include<vector>
#include<string>
using namespace std;

void illegal()
{
    cout <<"表达式不合法!" <<endl;
    exit(1);
}

bool isysf(char cc)
{
    if (cc==‘+‘ || cc==‘-‘ || cc==‘*‘ || cc==‘/‘) return true;
    else return false;
}

void JudgeLegalMid(string &c)
{
    int l=c.length();
    if (!isdigit(c[0]) && c[0]!=‘(‘) illegal();  //首位不是(也不是数字,不合法
    if (!isdigit(c[l-1]) && c[l-1]!=‘)‘) illegal();  //末位不是)也不是数字,不合法
    int now=0;  //括号不匹配,不合法
    for (int i=0;i<l;i++)
    {
        if (c[i]==‘(‘) now++;
        else if (c[i]==‘)‘) now--;
        if (now<0) illegal();
    }
    if (now!=0) illegal();
    for (int i=1;i<l-1;i++)
    {
        if (c[i]==‘+‘ || c[i]==‘*‘ || c[i]==‘/‘ || c[i]==‘-‘)  //二元运算符
        {
            if (!isdigit(c[i-1]) && c[i-1]!=‘)‘)  //左边不是)也不是数字,不合法
                illegal();
            if (!isdigit(c[i+1]) && c[i+1]!=‘(‘)  //右边不是(也不是数字,不合法
                illegal();
        }
        if (c[i]==‘.‘ && !isdigit(c[i-1]) && !isdigit(c[i+1])) illegal();  //.左右不是数字,不合法
    }
    for (int i=1;i<l;i++)  //.向左右扩展 ,在遇到运算符之前,只能扩展出数字才合法
    {
        if (c[i]==‘.‘)
        {
            int j=i-1,k=i+1;
            while (j>0 && isdigit(c[j])) j--;
            while (k<l && isdigit(c[k])) k++;
            if (c[j]==‘.‘ || c[k]==‘.‘) illegal();
        }
    }
}

第三步:中缀表达式转后缀表达式

  这一步是比较经典的栈处理,具体代码如下:(放在MidToPost.h文件中,封装成了类)

#ifndef MIDTOPOST_H____
#define MIDTOPOST_H____

#include<iostream>
#include<cstring>
#include<stack>
#include<vector>
#include<string>
#include<sstream>
using namespace std;

string cts(char cc)
{
    stringstream stream;
    stream << cc;
    return stream.str();
}

class MidToPost
{
    private:
        string c;
        stack<string> s;
        int yxj(char ope);  //返回一个运算符的优先级
    public:
        MidToPost(const string cc); //构造函数
        void ToPost(vector<string>& res);  //转为后缀表达式
        string readnum(int p);
};

int MidToPost::yxj(char ope)
{
    if (ope==‘*‘ || ope==‘/‘) return 1;
    if (ope==‘+‘ || ope==‘-‘) return 0;
    if (ope==‘@‘ || ope==‘(‘) return -1;
}

string MidToPost::readnum(int p)
{
    string s="";
    while (isdigit(c[p]) || c[p]==‘.‘)
    {
        s+=cts(c[p]);
        p++;
    }
    return s;
}

MidToPost::MidToPost(const string cc)
{
    c=cc;
    while (!s.empty()) s.pop();
    s.push(string("@"));
}

void MidToPost::ToPost(vector<string>& res)
{
    res.clear();
    int now=0;
    int l=c.length();
    for (int i=0;i<l;i++)
    {
        if (isdigit(c[i]))
        {
            res.push_back(readnum(i));
            while (isdigit(c[i]) || c[i]==‘.‘) i++;
            i--;
        }
        else if (c[i]==‘(‘) s.push(cts(c[i]));
        else if (c[i]==‘)‘)
        {
            while (s.top()[0]!=‘(‘)
            {
                res.push_back(s.top());
                s.pop();
            }
            s.pop();
        }
        else
        {
            int k1,k2;
            k1=yxj(s.top()[0]);
            k2=yxj(c[i]);
            while (k1>=k2)
            {
                res.push_back(s.top());
                s.pop();
                k1=yxj(s.top()[0]);
                k2=yxj(c[i]);
            }
            s.push(cts(c[i]));
        }
    }
    while (s.top()[0]!=‘@‘)
    {
        res.push_back(s.top());
        s.pop();
    }
}
#endif

第四步:计算后缀表达式的值

  同样是经典的栈处理,对于除数为0的情况由于C++自带inf所以就没有特判。代码如下:(放在CalcPost.h文件中)

#include<iostream>
#include<cstring>
#include<vector>
#include<string>
#include<vector>
#include<sstream>
using namespace std;

stack<double> s;

double Calc(vector<string> & c)
{
    while (!s.empty()) s.pop();
    int l=c.size();
    for (int i=0;i<l;i++)
    {
        if (isdigit(c[i][0]))
        {
            stringstream ss(c[i]);
            double tmp;
            ss >>tmp;
            s.push(tmp);
        }
        else
        {
            double res2=s.top();
            s.pop();
            double res1=s.top();
            s.pop();
            switch(c[i][0])
            {
                case ‘+‘:res1+=res2;break;
                case ‘-‘:res1-=res2;break;
                case ‘*‘:res1*=res2;break;
                case ‘/‘:res1/=res2;break;
            }
            s.push(res1);
        }
    }
    return s.top();
}

主程序:

#include"MidToPost.h"
#include"CalcPost.h"
#include"JudgeLegalMid.h"
#include"FormatMid.h"
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
using namespace std;

const int maxn=2000;
string mid;
vector<string> post;

int main()
{
    cout <<"请输入中缀表达式(实数加减乘除括号运算):";
    while (cin >>mid)
    {
        mid=FormatMid(mid);
        cout <<"等价转换后的中缀表达式:" <<mid <<endl;
        JudgeLegalMid(mid);
        MidToPost mtp(mid);
        mtp.ToPost(post);
        cout <<"后缀表达式:";
        for (int i=0;i<post.size();i++)
            cout <<post[i]<<" ";
        cout <<endl;
        cout <<"结果:" <<Calc(post) <<endl;
        cout <<"请输入中缀表达式(实数加减乘除括号运算):";
    }
    return 0;
}

运行结果:

时间: 2024-07-30 13:47:52

适用于实数范围的中缀表达式的 + - * / ( ) 计算(C++实现)的相关文章

关于中缀表达式的计算 和算符优先算法

中缀表达式计算:http://blog.sina.com.cn/s/blog_3fe961ae0100niq3.html 算符优先算法:http://blog.csdn.net/zhibudefeng/article/details/6937375 前中后缀表达式:http://blog.csdn.net/antineutrino/article/details/6763722/

中缀表达式及计算 栈的应用

未整理完.. #include<iostream> #include<cstdio> #include<queue> #include<stack> using namespace std; struct PostfixExpre { string infix; PostfixExpre(string _infix) { infix = _infix; } int getPri(char c) { switch(c){ case '(': return 1;

Infix expressions 中缀表达式

中缀表达式的计算 利用两个栈来实现,操作数栈,操作符栈 只支持个位数运算 最后必须输入一个'#' #include<iostream> using namespace std; template<typename ElementType> struct Node { ElementType data; Node<ElementType>* next; }; template<typename ElementType> class LinkStack { pu

数据结构——栈——中缀表达式和后缀表达式

什么是中缀表达式,什么是后缀表达式 我们一般看见的多项式计算都是中缀表达式构成的:1+2*3+4/3 类似这种,为什么说是中缀呢?因为它的计算符号都是在两个数中间的. 那么自然而然的明白了后缀表达式是一种计算符号在两个数后面的. 如123*+43/+ 中缀表达式和后缀表达式有什么关系? 其实仔细你就会发现,上面给出的式子其实都是一样的,只是计算的顺序在后缀表达式中你看不懂而已. 因为我们习惯去看中缀表达式的计算. 其实他们之间是可以互相转换的.他们也可以表达同一个意思,同一个计算式子. 为什么会

中缀表达式求值

中缀表达式用于计算一个表达式,比如计算器 就是这样实现的 这儿是用栈的数据结构来实现的.首先输入一个字符串,表示一个表达式,然后用一个栈存储数字,另外一个栈存储符号 如果当前运算符优先级比栈顶元素优先级高,则入栈,若当前运算符优先级小于等于栈顶运算符优先级,则从数字栈中弹出两个元素,从符号栈中弹出一个符号,计算结果入栈(数字栈): 代码如下: #include<iostream> using namespace std; #include<cstring> #include<

中缀表达式转后缀表达式---栈--二叉树---四则运算

我们平常书写的四则运算表达式属于中缀表达式,形式为"9+(3-1)*3+10/2",因为所有的运算符号都在两操作数之间,所以称为中缀表达式.我们使用中缀表达式来计算表达式的值,不过这种形式并不适合计算机求解.接下来,我们将中缀表达式转化为后缀表达式,所谓的后缀表达式就是操作符位于操作数后面的不包含括号的算数表达式,也叫做逆波兰表达式. 1)首先介绍一种人工的转化方法(http://www.cnblogs.com/MichaelYin/archive/2012/05/02/2479248

中缀表达式与后缀表达式

计算中缀表达式"可以称得上是一个特别经典的关于栈的算法题,几乎在所有数据结构教材中都会涉及,而且很多公司面试或者笔试的时候都会把这道题作为一个考察点.可以说,这是一道必须要掌握的算法题.中缀表达式.后缀表达式等概念在这里就不赘述了,让我们直奔主题.题目:输入一个中缀表达式,计算其结果.输入的前提假设:(1)只考虑+.-.*./这四种运算符,中缀表达式中只有一种括号:():(2)输入的中缀表达式中只有整数,没有小数:(3)假定输入是合法的.很多文章或课本喜欢一步到位,直接讨论如何从中缀表达式计算结

什么是中缀表达式与后缀表达式

一.中缀表达式转化为后缀表达式表达式与后缀表达式 在日常应用中,算术表达式中运算符总是出现在两个操作数之间,例如5*(7-2*3)+8/2,这种形式称为中缀表达式.计算一个中缀表达式需要知道运算符的优先级和结合性.乘除是高优先级,加减是低优先级,优先级相同时他们都是左结合的,也就是从左计算到右.有括号就要计算括号内的表达式. 中缀表达式利于人的理解,但不便于计算机的处理. 因此需要将中缀表达式转换成后缀表达式,以方便计算机处理.所谓后缀表达式就是将运算符放在运算数之后.后缀表达式也称为逆波兰表达

【算法学习笔记】86.栈 中缀表达式 SJTU OJ 1033 表达式计算

...被输入给坑了 应该先把所有的空格删掉再玩  还有就是测试点里好像根本就没有关于后结合的事情...不过后结合也很简单 控制一下优先级的判断即可. 中缀表达式的处理核心就是两个堆栈的维护 一个是 操作符 一个是 操作数 只有当 当前正在处理的操作符的优先级大于(不考虑后结合时) 栈顶操作符的时候, 才进行计算.(或者出现右括号时 一直计算到左括号出现) 代码比较长 用了struct来存储token 比较清晰. #include <iostream> #include <stack>