版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、表达式计算-C+1, 这是使用C+编写的一个表达式转后缀式再求值的一个类2, 由于本人只是学生一个,这些都是为了验证学习上的东西,写得比较粗糙,只供初学者参考3, 本类可以计算小数,负数。只能识别+ - * / % (这是一个乘方运算符,用法如:216计算2的16次方,%这是一个求余运算符,使用规则和C+编译器类似),只能包含()这一种括号,并且在操作数和括号之间的运算符不能省略,每个运算符要明确给出4, 本类负数处理的方法是采用:符号来替换,可以在表达式中输入(-)负号,但在字符检测函数来区分负号时,如果检测出来是负号就会自动转换为(:)这个符号。这主要是为了在以后计算时可以不用每次来区分是
2、不是负号,而只区分一次即可。也可以直接在表达式中用:这个符号来表示负号,识别函数可以直接识别而不需要区分和替换。要注意的是,(-)这种负号一定要使用表达式检查函数才能识别,如果不想使用检查函数,就只能用:来代替。5, 本类的表达式检查函数会按照一定的规则来检测表达式输入是否合要求,如果有不合要求的字符或字符位置不合要求都会报错,并会指出是那一个字符,而且当函数检测到一个错误时不会立即停下,而会继续检测,只到表达式结束。并输出表达式中的那些字符不合要求。6, 单个0是不能出现在表达式中,但0.0可以,如果表达式中需要出0可以用0.0代替,但如:30/0.0这样的计算会在计算时给出错误提示。7,
3、表达式中可以出现-(-(-13+5)+5)这样的深层负号计算,计算结果和VC+编译器结果一样8, 本类在VC6.0,w7系统下编译通过并运算。9, 本类中没有主动清空数据成员的方法,所以有使用时,要将类的对象定义在计算循环或函数内,这样每一次计算都会对对象进行创建和析构,不然会出现异常,当然你可以增加一个清空数据成员的方法。/以下是ExpEvaluate.h类的头文件#ifndef Exp_h#define Exp_h#include <string> /字符串类头文件#include <stack> /STL栈头文件#include <queue> /ST
4、L队列头文件#include <vector> /STL向量头文件#include <list> /STL链表头文件using namespace std;class ExpEvaluatepublic:ExpEvaluate(); /用于初始化错误列表void ExpInto(string &Exp); /输入一个表达式int ExpDetector(); /字符串规则检测函数int ExpIdentification(char Exp); /数字运算符识别函数int ExpPriority(char Ope); /返回运算符的优先级void ExpSuffi
5、x(); /将表达式转为后缀式double ExpCompute(); /计算后缀表达式,并返回结果void ErrorBacktrack(); /根据错误号返回相应错误private:string exps; /表达式字符串stack<char> oper; /运算符栈stack<double> operand; /操作数栈queue<char> postfix; /后缀队列vector<char *> error; /错误列表list<int> index; /错误索引表int grade; /错误标号string errorou
6、t; /错误输出缓冲区double OpReadop(); /读取操作数,并返回转换后的结果double OpOrder(double op,double x); /求op数的x次方;#endif/以下是.cpp实现文件#include "ExpEvaluate.h"#include "resource.h"#include <stdlib.h> /字符转换数字头文件#include <windows.h>#include <iostream.h>ExpEvaluate:ExpEvaluate()/初始错误列表erro
7、r.resize(15); /为列表初始为15个元素grade=0; /初始标号为0,表示没有错误 error.at(0)=" 操作数错误:操作数前不能是)右括号!"error.at(1)=" 操作数错误:0不可以出现在操作的开始,也不能作为一个单独的操作数!"error.at(2)=" 操作数错误:小数点不能在一个操作数中重复出现!"error.at(3)=" 运算符错误:运算符前面必须是操作数或)右括号,并且运算符不能重叠!"error.at(4)=" 括号错误: 左括号前面必须是运算符或左括号或负号
8、!"error.at(5)=" 括号错误: 右括号前面必须是操作数或右括号!"error.at(6)=" 括号错误: 括号输入不匹配!"error.at(7)=" 分隔符错误:#号分隔符只能出现在表达式的边界位置!"error.at(8)=" 表达式错误:表达式的结尾必须是操作数或右括号!"error.at(9)=" 负号错误: 负号前面必须是运算符或左括号呀分隔符!"error.at(10)=" 字符错误: 表达式中除数字,运算符,:负号,()括号之外不能出现其它符号!&q
9、uot;error.at(11)=" 计算错误: 除数不能为0,也不能小于0.0001(个人限制)!"error.at(12)=" 计算错误: 求余运算中,除数不能为0或小于0!"error.at(13)=" 计算错误: 次方运算中,次方数不能小于0!"error.at(14)=" 计算错误: 计算结果出现错误!"void ExpEvaluate:ErrorBacktrack()list<int>:iterator pexp; /使用迭代器来遍历链表char m18; /字符缓冲区if(grade=0)
10、 /如果错误标号为0表示没有错误,就直接返回return;else if(grade=1) /如果为1表示错误由检测函数发现for(pexp=index.begin();pexp!=index.end();) /通过sprintf函数将错误的字符位置整数,格式化到字符缓冲区数组m中sprintf(m,"错误字符位置:%2d",*pexp);errorout+=m; /将格式化的字符连接到错误输出缓冲区中pexp+;errorout+=error.at(*pexp); /将相对应的错误提示连接至缓冲区中errorout+="rn" pexp+; cout&
11、lt;<errorout<<endl;/输出错误else if(grade=2) /如果错误标号为2,表示是在计算时发现for(pexp=index.begin();pexp!=index.end();) /将相应的错误连接到错误缓冲区中errorout+=error.at(*pexp);errorout+="rn"pexp+; cout<<errorout<<endl;/输出错误int ExpEvaluate:ExpIdentification(char Exp) /数字运算符识别函数 int iexp=(int)Exp;if(i
12、exp=46|iexp>=48&&iexp<=57)return 1; /表示识别到的是数字和小数点switch(iexp)case 94: case 37:case 43:case 45:case 42:case 47: return 2; /表示识别到+-*/运算符case 40:case 41:return 3; /表示识别到括号case 35: return 4; /如果是#号,这只是一个分隔符,没有其它含意case 58: return -1; /用这个符号来替换负号,表示识别到一个负号return 0; /表示识别到其它运算符int ExpEvaluat
13、e:ExpPriority(char Ope) /返回运算符的优先级 switch(Ope)case '':return 4; /赋于次方运算符最高优先级case '%':case '*':case '/':return 3; /赋于*,/,%侁先级case '+':case '-':return 2; case '(': return 1;return 0; /如果不是运算符就返回0void ExpEvaluate:ExpInto(string &Exp) /输入一个表达式
14、if(Exp.empty()return;exps=Exp; /将表达式输入到类中exps.insert(0,'#'); /在表达式的边界加入一个分隔符,以简化规则检测exps+='#'return;int ExpEvaluate:ExpDetector() /字符串规则检测函数,采用向前检测 int i=1,frequency=0; /frequency为小数点标志,每一个操作数能出现一位小数点int sign=1; /如果出现错误就将标志位改为0,否则就不改变char interspace;while(i<exps.size() /一直读到最后一个字符
15、 interspace=exps.at(i);switch(ExpIdentification(interspace) /判断每一个字符是否合规则case 1: /如果是操作数if(exps.at(i-1)=')')index.push_back(i); /记录错误位置index.push_back(0); /记录错误信息号grade=1; /将标志位至1,说明是检测函数检测的错误 sign=0; /如果有错误就将返回标志至0break;else if(interspace='0')/对0进行特别检测if(ExpIdentification(exps.at(i-
16、1)!=1) /如果0出现在一个操作数的开始,那这个数必须为小数if(exps.at(i+1)!='.') /如果如果不是小数就算是非法数index.push_back(i); index.push_back(1);grade=1; sign=0;break;else if(interspace='.')/如果操作数中出现小数点,就必须将其标志,心防止出现多个小数点if(frequency=1)index.push_back(i); /记录错误位置index.push_back(2); /记录错误信息号grade=1; /将标志位至1,说明是检测函数检测的错误
17、sign=0; /如果有错误就将返回标志至0break;elsefrequency=1; /如果操作数中出现小数点就将标志置1break;case 2: /需要检测运算符是否合规则,并检测负号frequency=0; /如果出现运算符就说明是另一个操作数,这时需要将小数点标志置0 if(interspace='-') /如果是-号就需要判断是运算还是负号 if(ExpIdentification(exps.at(i-1)=2|exps.at(i-1)='('|exps.at(i-1)='#')/如果-号前面是运算符或(括号或#号并且后面要是数字,
18、这样就说明-号是负号 exps.replace(i,1,":"); /如果是负号就将它替换为:号break;if(ExpIdentification(exps.at(i-1)!=1 && exps.at(i-1)!=')')/如果运算符的前面不是操作数或不是)括号,index.push_back(i);index.push_back(3);grade=1; sign=0;break;break;case 3: /需要检测括号是否合规则if(interspace='(')if(ExpIdentification(exps.at(
19、i-1)!=2 && exps.at(i-1)!=':' && exps.at(i-1)!='(' && exps.at(i-1)!='#') /增加&& exps.at(i-1)!=':'这个条件就可以处理-(-(12+3)+3)这样的多层嵌套负号计算功能index.push_back(i);index.push_back(4);grade=1; sign=0; oper.push(interspace); /是左括号就压栈else if(ExpIdentifica
20、tion(exps.at(i-1)!=1 && exps.at(i-1)!=')')/如果右括号前面必须是操作数或右括号index.push_back(i);index.push_back(5);grade=1; sign=0;if(oper.empty()|oper.top()!='(')index.push_back(i);index.push_back(6);grade=1; sign=0; elseoper.pop(); /如果右括号匹配就将括号弹出break;case 4: /如果读到分隔符,这个在这里只能出现在边界if(i!=0 &a
21、mp;& i!=exps.size()-1)index.push_back(i);index.push_back(7);grade=1; sign=0;elseif(ExpIdentification(exps.at(i-1)!=1 && exps.at(i-1)!=')')/如果结尾处不是操作数或右括号就出错index.push_back(i);index.push_back(8);grade=1; sign=0;break;case -1: /如果读到负号if(ExpIdentification(exps.at(i-1)!=2 &&
22、exps.at(i-1)!='(' && exps.at(i-1)!='#')index.push_back(i);index.push_back(9);grade=1; sign=0;break;case 0: /如果读到非法字符就输出相应提示index.push_back(i);index.push_back(10);grade=1; sign=0;break;i+;if(!oper.empty() /如果括号匹配栈不为空就输出错误提示index.push_back(i-1); /记录错误字符位置index.push_back(6); /记录
23、相对应的错误信息号grade=1; /将标志修改为1,不示是检测函数发现的错误 sign=0; /将返回值标志至0,表示有错误while(!oper.empty() /如果不为空就将它清空oper.pop();return sign; /sign为1表示表达式无错误,为0表示有错误/当返回值为0,就调用错误输出函数来输出错误double ExpEvaluate:OpOrder(double op,double x)int n=(int)x,i; /参数x之所以定为浮点型是为了简化操作double sum=1;if(n=0)/0的任何次方都为1 return 1;for(i=0;i<n;i
24、+)sum*=op; /获取op的x次方return sum;void ExpEvaluate:ExpSuffix() /将表达式转为后缀式int i=0;char interspace,m;while(i<exps.size()interspace=exps.at(i);switch(ExpIdentification(interspace)case 1: /如果读到的是操作数就直接入后缀 postfix.push(interspace);break;case -1: /如果是负号就判断是否是-(12+3)之类的表达式 postfix.push(interspace);/先将负号直接入
25、后缀if(exps.at(i+1)='(') /判断负号的下一位是不是左括号 /如果下一位是括号,说明就是-(12+3)这种情况,遇到这种就将负号改为-0- postfix.push('0'); /加上0就将负号变为-0操作数了 postfix.push('#'); /将负号变为-0操作数后要记得加上分隔符oper.push('-'); /并要加上一个减号,(这样可以达到负负得正,正负得负的目的)/这里的思想是将-(12+3)替换为-0-(12+3),这样就可以处理-(-(-()这样的负号break;case 2:/如果读到的是运
26、算符就压入运算符栈postfix.push('#'); /连续操作数之间用#号隔开if(oper.empty()oper.push(interspace); /如果栈为空就直接压入栈else /如果栈不空就要比较运算的优先级while(ExpPriority(interspace)<=ExpPriority(oper.top()m=oper.top(); /如果小于或等于就将栈中运算符弹出至后缀队列postfix.push(m);oper.pop(); /弹出至后缀队列后就删除if(oper.empty()break; /如果运算符栈为空就结束循环oper.push(in
27、terspace); /如果读到的运算符大于栈中运算符就直接压入break;case 3:/如果读到括号if(interspace='(')oper.push(interspace); /如果读到的是左括号就直接入运算符栈elsewhile(oper.top()!='(') /如果读到右括号就在运算符栈中寻找左括号 /并将左括号和右括号之间的运算符全部弹出至后缀队列postfix.push(oper.top();oper.pop();if(oper.top()='(') /最后再将左括号删除oper.pop();break;i+;while(!o
28、per.empty() /最后再将栈中的运算符全部弹出至后缀队列m=oper.top();postfix.push(m);oper.pop();double ExpEvaluate:OpReadop() /读取操作数,并返回转换后的结果char data80; /用64个字符空间作为操作数缓冲区int i=0;double f=0;while(ExpIdentification(postfix.front()!=2 && ExpIdentification(postfix.front()!=4)if(ExpIdentification(postfix.front()=-1)/如
29、果是负号需要再转换datai='-'postfix.pop(); /转换后要删除i+;if(postfix.empty()break; /如果后缀为空就结束循环elsedatai=postfix.front();postfix.pop(); /读取后就删除i+;if(postfix.empty()break; /如果后缀为空就结束循环datai='0' /读完后要加上结束符f=atof(data); /并转换return f; /转换后返回结果double ExpEvaluate:ExpCompute() /计算后缀表达式,并返回结果double op1,op2
30、;while(!postfix.empty()switch(ExpIdentification(postfix.front()case 1:case -1:operand.push(OpReadop(); /如果是操作数就调用读操作数函数来返回转换后的操作数break;case 4:postfix.pop(); /如果是分隔符就直接删除break;case 2: /如果读到的是运算符就计算op2=operand.top(); /先弹出的是操作数2operand.pop(); /操作数取完就删除op1=operand.top();operand.pop();switch(postfix.front()case '+
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 度社团工作总结报告
- (完整版)医疗器械从业人员上岗资格考试试题及答案
- 2026年心肺复苏考试题(+答案)
- 金属冶炼企业职业卫生管理制度
- 棉纺织企业安全教育培训制度
- 2026年设备监理师之设备工程监理基础及相关知识全真模拟考试试卷含答案
- 金属粉尘企业铣工运行操作安全操作规程
- 临床医师三基考试试题及答案
- 人力资源薪酬管理制度及实施方案
- 2026行为法面试题库及答案
- 2026上海博物馆公开招聘12名工作人员备考题库及参考答案详解
- 2026年山东定期医师考核题库及答案
- 骨关节炎阶梯治疗专家共识(2026版)
- 《工业管道安全技术规程》(TSG31-2025)监督检验规则培训
- 小学6年级暑假每日学习打卡表(可直接打印使用)
- 2026年山东聊城市社区工作者考试试题解析及答案
- 供电公司计量采集培训
- 关节腔内注射药物治疗类风湿关节炎的医药专家共识
- 2026年电气工程及其自动化专业考研模拟单套试卷(含重点难点)
- 初一语文课文必背古诗词
- 放射工作人员培训课件
评论
0/150
提交评论