核心算法:

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=;i<mid.length();i++)
{
if (mid[i]=='-' && (i==||mid[i-]=='('))
{
mid.insert(i,"");
i++;
}
}
string realmid="";
for (int i=;i<mid.length();i++)
{
if (mid[i]!='-')
{
realmid+=mid[i];
}
else
{
int cou=;
while (mid[i]=='-') i++,cou++;
if (cou%==) realmid+='+';
else realmid+='-';
i--;
}
}
return realmid;
}

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

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

#include<iostream>
#include<cstring>
#include<vector>
#include<string>
using namespace std; void illegal()
{
cout <<"表达式不合法!" <<endl;
exit();
} 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[]) && c[]!='(') illegal(); //首位不是(也不是数字,不合法
if (!isdigit(c[l-]) && c[l-]!=')') illegal(); //末位不是)也不是数字,不合法
int now=; //括号不匹配,不合法
for (int i=;i<l;i++)
{
if (c[i]=='(') now++;
else if (c[i]==')') now--;
if (now<) illegal();
}
if (now!=) illegal();
for (int i=;i<l-;i++)
{
if (c[i]=='+' || c[i]=='*' || c[i]=='/' || c[i]=='-') //二元运算符
{
if (!isdigit(c[i-]) && c[i-]!=')') //左边不是)也不是数字,不合法
illegal();
if (!isdigit(c[i+]) && c[i+]!='(') //右边不是(也不是数字,不合法
illegal();
}
if (c[i]=='.' && !isdigit(c[i-]) && !isdigit(c[i+])) illegal(); //.左右不是数字,不合法
}
for (int i=;i<l;i++) //.向左右扩展 ,在遇到运算符之前,只能扩展出数字才合法
{
if (c[i]=='.')
{
int j=i-,k=i+;
while (j> && 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 ;
if (ope=='+' || ope=='-') return ;
if (ope=='@' || ope=='(') return -;
} 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=;
int l=c.length();
for (int i=;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()[]!='(')
{
res.push_back(s.top());
s.pop();
}
s.pop();
}
else
{
int k1,k2;
k1=yxj(s.top()[]);
k2=yxj(c[i]);
while (k1>=k2)
{
res.push_back(s.top());
s.pop();
k1=yxj(s.top()[]);
k2=yxj(c[i]);
}
s.push(cts(c[i]));
}
}
while (s.top()[]!='@')
{
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=;i<l;i++)
{
if (isdigit(c[i][]))
{
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][])
{
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=;
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=;i<post.size();i++)
cout <<post[i]<<" ";
cout <<endl;
cout <<"结果:" <<Calc(post) <<endl;
cout <<"请输入中缀表达式(实数加减乘除括号运算):";
}
return ;
}

运行结果:

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

  1. C语言数据结构之栈:中缀表达式的计算

    *注:本人技术不咋的,就是拿代码出来和大家看看,代码漏洞百出,完全没有优化,主要看气质,是吧 学了数据结构——栈,当然少不了习题.习题中最难的也是最有意思的就是这个中缀表达式的计算了(可以算+-*/和 ...

  2. C++实现顺序栈类求解中缀表达式的计算

    控制台第一行打印的数值为使用形如以下方式得到的结果: cout << +*(+)*/- << endl; 即第一个待求解表达式由C++表达式计算所得结果,以用于与实现得出的结果 ...

  3. Java堆栈的应用2----------中缀表达式转为后缀表达式的计算Java实现

    1.堆栈-Stack 堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除 ...

  4. Infix expressions 中缀表达式

    中缀表达式的计算 利用两个栈来实现,操作数栈,操作符栈 只支持个位数运算 最后必须输入一个'#' #include<iostream> using namespace std; templ ...

  5. c语言,中缀表达式转后缀表达式并计算

    //c语言中缀表达式计算 #include <stdio.h> #include <stdlib.h> #include <string.h> #include & ...

  6. Python与数据结构[1] -> 栈/Stack[1] -> 中缀表达式与后缀表达式的转换和计算

    中缀表达式与后缀表达式的转换和计算 目录 中缀表达式转换为后缀表达式 后缀表达式的计算 1 中缀表达式转换为后缀表达式 中缀表达式转换为后缀表达式的实现方式为: 依次获取中缀表达式的元素, 若元素为操 ...

  7. 利用stack结构,将中缀表达式转换为后缀表达式并求值的算法实现

    #!/usr/bin/env python # -*- coding: utf-8 -*- # learn <<Problem Solving with Algorithms and Da ...

  8. RPN-逆波兰计算器-中缀表达式转后缀表达式-javascript

    1.利用栈(Stack)来存储操作数和操作符: 2.包含中缀表达式转后缀表达式的函数,这个是难点,也是关键点: 2.1.将输入字符串转为数组: 2.2.对转换来的字符进行遍历:创建一个数组,用来给存储 ...

  9. 中缀表达式转后缀表达式(用于求字符串表达式值)(js栈和队列的实现是通过数组的push和unshift方法插值,pop方法取值)

    中缀表达式:就是我通常用的算术或逻辑公式: 后缀表达式:不包含括号,运算符放在两个运算对象后面,所有的计算按运算符出现的顺序,严格从左向右进行,不用考虑运算符优先级: 如,(2+1)*3 转换后,2 ...

随机推荐

  1. WebSocket 的使用

    Java 控制台程序实现类似广播功能 服务器端代码 添加 maven 依赖 <dependency> <groupId>javax.websocket</groupId& ...

  2. linux io 学习笔记(03)---共享内存,信号灯,消息队列

    system V IPC 1)消息队列 2)共享内存 3)信号灯(信号量集) 1.消息队列. ipcs -q 查看系统中使用消息队列的情况 ipcrm -q +msqid 删除消息队列 消息队列工作原 ...

  3. 使用USB Key(加密狗)实现身份认证

    首先你需要去买一个加密狗设备,加密狗是外形酷似U盘的一种硬件设备! 这里我使用的坚石诚信公司的ET99产品 公司项目需要实现一个功能,就是客户使用加密狗登录, 客户不想输入任何密码之类的东西,只需要插 ...

  4. 【面试题】2018年最全Java面试通关秘籍第五套!

    [面试题]2018年最全Java面试通关秘籍第五套! 原创 2018-04-26 徐刘根 Java后端技术 第一套:<2018年最全Java面试通关秘籍第一套!> 第二套:<2018 ...

  5. Delphi实例之一个简易的浏览器的实现

    Delphi实例之一个简易的浏览器的实现 Delphi7的WebBrowser组件提供了很多不错的网页设计的功能,下面做一个简单的浏览器.组件很简单按照下面摆放就行了. 这是运行后的效果 源代码 主页 ...

  6. 基于阿里云服务器Linux系统部署JavaWeb项目

    前段时间刚完成一个JavaWeb项目,想着怎么部署到服务器上,边学边做,花了点时间终于成功部署了,这里总结记录一下过程中所遇到的问题及解决方法.之所以选择阿里云,考虑到它是使用用户最多也是最广泛的云服 ...

  7. 《python核心编程第二版》第7章习题

    7–1. 字典方法.哪个字典方法可以用来把两个字典合并到一起? 答:dict1.update(dict2) 7–2. 字典的键.我们知道字典的值可以是任意的Python 对象,那字典的键又如何呢?请试 ...

  8. 再见NullPointerException。在Kotlin里null的处理(KAD 19)

    作者:Antonio Leiva 时间:Apr 4, 2017 原文链接:https://antonioleiva.com/nullity-kotlin/ 关于Kotlin最重要的部分之一:无效处理, ...

  9. (转)简述47种Shader Map的渲染原理与制作方法

    在Shader中会使用各种不同图参与渲染,所以简单地总结下各种图的渲染原理.制作方法,最后面几种是程序生成图. 1. Albedo 2. Diffuse(Photographic) 从上图可以看出来, ...

  10. Gated Recurrent Unit (GRU)

                                   Gated Recurrent Unit (GRU) Outline                             Backgr ...