这次发表的是本人一个周末完成的中缀表达式转换为后缀表达式并求值的一个程序,采用了STL的stack对象,并用了不少标准库中string相关的方法,供各位参考,并欢迎提出改进意见。
其实,STL中的stack与自己定义stack对象并无实质不同,如不打算用STL,定义一个堆栈的结构体即可。
程序中有若干注释掉的源码与说明,是调试过程中所用,在此暂不删除,以体现手工调试的艰辛。
程序结构:
myDtsr.h 为该程序头文件,声明用到的函数
myDstr.cpp 为函数实现文件
cnsCalc.cpp为主文件
// myDstr.h文件 #include<stack> #include<string> #include<iostream> using namespace std; //表达式转换与计算堆栈声明 #ifndef _STACK_H #define _STACK_H extern stack<int>stackTrans; extern stack<float>stackCalc; #endif //获得运算符优先级的函数声明 extern int intPrioper(int intOper); //判断堆栈为满或空的函数声明(有重载) extern bool bolStackfull(stack<float> &stackTarget); extern bool bolStackempty(stack<float> &stackTarget); extern bool bolStackfull(stack<int> &stackTarget); extern bool bolStackempty(stack<int> &stackTarget); //从堆栈中置入元素和获得元素的函数(有不同类型定义) extern float flaGetstack(stack<float> &stackTarget); extern float flaPutstack(float flaElem,stack<float> &stackTarget); extern int intGetstack(stack<int> &stackTarget); extern int intPutstack(int intElem,stack<int> &stackTarget); //清空目标堆栈的函数声明(有不同类型定义) extern stack<float> &stackClear(stack<float> &stackTarget); extern stack<int> &stackClear(stack<int> &stackTarget); //获取后缀表达式函数声明 extern string &strEndget(string &strInput); //获取中缀表达式函数声明 extern string &strMidget(string &strInput); //后缀表达式求值函数声明 extern float flaEndcalc(string &strInput,stack<float> &stackInput); //中缀转后缀表达式函数声明 extern string &strTransmidend(string &strInput,string &strOutput,stack<int> &stackInput);
// myDstr.cpp文件 #include"myDstr.h" //数值范围判断 const int INTASCZER=0x30; const int INTASCNIN=0x39; //栈的最大高度 const int INTSTACKMAX=100; //表达式转换与计算堆栈定义 stack<int>stackTrans; stack<float>stackCalc; //运算符优先级的枚举定义 enum enmPrioper { ENM_MUL=3, ENM_DIV=3, ENM_ADD=2, ENM_SUB=2, ENM_LBCK=1, ENM_END=0, ENM_DEF=-1 }; //获得运算符优先级的函数实现(该函数主要用于中后缀转换) int intPrioper(int intOper) { switch(intOper) { case '*': return ENM_MUL; case '/': return ENM_DIV; case '+': return ENM_ADD; case '-': return ENM_SUB; case '(': return ENM_LBCK; case '#': return ENM_END; default: return ENM_DEF; } } //检测堆栈是否为空和满的函数实现(有重载) bool bolStackfull(stack<float> &stackTarget) { if (stackTarget.size()>INTSTACKMAX) { cout<<"Stack is full!"<<endl; return true; } return false; } bool bolStackempty(stack<float> &stackTarget) { if(stackTarget.empty()) { //cout<<"Stack is empty!"<<endl; return true; } return false; } bool bolStackfull(stack<int> &stackTarget) { if (stackTarget.size()>INTSTACKMAX) { cout<<"Stack is full!"<<endl; return true; } return false; } bool bolStackempty(stack<int> &stackTarget) { if(stackTarget.empty()) { //cout<<"Stack is empty!"<<endl; return true; } return false; } //从堆栈中获得元素和置入元素的函数(有不同类型定义) float flaGetstack(stack<float> &stackTarget) { if(!bolStackempty(stackTarget)) { float flaTemp=stackTarget.top(); stackTarget.pop(); //cout<<"get "<<flaTemp<<" from stack"<<endl; return flaTemp; } } float flaPutstack(float flaElem,stack<float> &stackTarget) { if(!bolStackfull(stackTarget)) { stackTarget.push(flaElem); //cout<<"push "<<flaElem<<" to stack"<<endl; return 0; } } int intGetstack(stack<int> &stackTarget) { if(!bolStackempty(stackTarget)) { int intTemp=stackTarget.top(); stackTarget.pop(); //cout<<"get "<<intTemp<<" from stack"<<endl; return intTemp; } } int intPutstack(int intElem,stack<int> &stackTarget) { if(!bolStackfull(stackTarget)) { stackTarget.push(intElem); //cout<<"push "<<intElem<<" to stack"<<endl; return 0; } } //清空stack函数实现(有不同类型定义) stack<float> &stackClear(stack<float> &stackTarget) { while(!stackTarget.empty()) { stackTarget.pop(); } return stackTarget; } stack<int> &stackClear(stack<int> &stackTarget) { while(!stackTarget.empty()) { stackTarget.pop(); } return stackTarget; } //获取后缀表达式函数实现 string &strEndget(string &strInput) { cout<<"Please input RPN notation!"<<endl; cin>>strInput; return strInput; } //获取中缀表达式函数实现 string &strMidget(string &strInput) { cout<<"Please input general notation!"<<endl; cin>>strInput; return strInput; } /* 后缀表达式求值函数 根据Donald Knuth定义的后缀表达式计算方法 (1)初始化一个空堆栈 (2)从左到右读入后缀表达式 (3)若字符是一个操作数,把它压入堆栈 (4)若字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈;若不能够弹出两个操作数,后缀表达式的语法就不正确 (5)到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,那么堆栈应该为空 strInput:计算的目标表达式 stackInput:计算过程中所用的堆栈 */ float flaEndcalc(string &strInput,stack<float> &stackInput) { //无条件的先清空目标堆栈 stackInput=stackClear(stackInput); //准备查找数值的子串 string strSubnum("0123456789"); string::size_type sztPos=0; string strSubtemp; for(int iCycle=0;iCycle<(int)strInput.size();iCycle++) { //若首字符为数字 if(isdigit(strInput[iCycle])) { //获得字符后转换为整数 //float flaTemp=strInput[iCycle]-INTASCZER; //以非数值字符为界截取子串并转换 sztPos=strInput.find_first_not_of(strSubnum,iCycle); strSubtemp=strInput.substr(iCycle,sztPos-iCycle); int intTemp=atoi(strSubtemp.c_str()); //将操作数置入堆栈 flaPutstack(intTemp,stackInput); //上述处理完毕后将循环变量在前端位置重新定位 iCycle=sztPos; } //取得操作符后进行运算 else if(('+'==strInput[iCycle]) || ('-'==strInput[iCycle]) || ('*'==strInput[iCycle]) || ('/'==strInput[iCycle])) { float flaNum1,flaNum2,flaNumcalc; flaNum1=flaGetstack(stackInput); flaNum2=flaGetstack(stackInput); switch (strInput[iCycle]) { case '+': flaNumcalc=flaNum2+flaNum1; break; case '-': flaNumcalc=flaNum2-flaNum1; break; case '*': flaNumcalc=flaNum2*flaNum1; break; case '/': flaNumcalc=flaNum2/flaNum1; break; default: break; } //结果置入堆栈 flaPutstack(flaNumcalc,stackInput); } else { cout<<"The RPN syntax is error!"<<endl; return -1; } } //最终取得堆栈中存储的结果即为表达式最终值 float flaResult; flaResult=flaGetstack(stackInput); if(bolStackempty(stackInput)) cout<<"The result of RPN is "<<flaResult<<endl; else cout<<"The RPN syntax is error!"<<endl; return 0; } /* 中缀转后缀表达式函数 (1)初始化一个空堆栈,将结果字符串变量置空 (2)从左到右读入中缀表达式,每次一个字符 (3)如果字符是操作数,将它添加到结果字符串 (4)如果字符是个操作符,若栈为空则直接将该操作符入栈,否则先把高于当前操作符优先级的运算符出栈后加入输出表达式,然后把该操作符入栈 (5)如果字符是个左括号,把它压入堆栈 (6)如果字符是个右括号,在遇见左括号前,弹出所有操作符,然后把它们添加到结果字符串并最终删除左括号 (7)如果到达输入字符串的末尾,弹出所有操作符并添加到结果字符串 strInput:用于传入输入的表达式 strOutput:接收经过转换的结果输出 stackInput:用于进行转换的堆栈 */ string &strTransmidend(string &strInput,string &strOutput,stack<int> &stackInput) { //test //cout<<"Start transmidend"<<endl; //初始化清空输出字符串与表达式堆栈 strOutput.clear(); stackClear(stackInput); //无条件将strInput后加#作为终止条件同时用#初始化堆栈 //此处添加#则可省略手工输入时对中缀表达式添加的# intPutstack('#',stackInput); strInput.push_back('#'); //开始读取并转换 for(int iCycle=0;iCycle<(int)strInput.size();iCycle++) { //遇到数字直接加入后缀表达式 if(isdigit(strInput[iCycle])) { strOutput.push_back(strInput[iCycle]); if(!isdigit(strInput[iCycle+1])) strOutput.push_back(' '); //test //cout<<strOutput<<endl; } //遇到操作符的处理 else if(('+'==strInput[iCycle]) || ('-'==strInput[iCycle]) || ('*'==strInput[iCycle]) || ('/'==strInput[iCycle])) { //if(bolStackempty(stackInput)) if('#'==stackInput.top()) intPutstack(strInput[iCycle],stackInput); else { //将所有高于当前优先级的运算符出栈并加入输出表达式 while(intPrioper(stackInput.top())>=intPrioper(strInput[iCycle])) { strOutput.push_back(intGetstack(stackInput)); //test //cout<<strOutput<<endl; } //完成上述工作后将当前运算符入栈 intPutstack(strInput[iCycle],stackInput); } } //遇到左括号则直接入栈 else if('('==strInput[iCycle]) intPutstack(strInput[iCycle],stackInput); //遇到右括号,则在遇见左括号前,弹出遇到的所有操作符,然后把它们添加到结果字符串,并删除左括号 else if(')'==strInput[iCycle]) { while(intPrioper(stackInput.top())>=ENM_LBCK) //(栈顶端优先级判断>ENM_LBCK)可确保栈顶元素既不是左括号同时也是操作符 { if('('==stackInput.top()) intGetstack(stackInput); else { strOutput.push_back(intGetstack(stackInput)); } } } //到输入字符串末尾 if('#'==strInput[iCycle]) //if(iCycle==(int)(strInput.size()-1)) { //cout<<"notation end!!"<<endl; while(intPrioper(stackInput.top())>ENM_END) //(栈顶端优先级判断>ENM_END)可确保栈顶元素为常规操作符 { strOutput.push_back(intGetstack(stackInput)); //test //cout<<strOutput<<endl; } } }//for循环的终止标记 //test cout<<strOutput<<endl; return strOutput; }
// 该文件为主文件 #include"myDstr.h" int main() { //接收一个求值表达式输入串 string strEnd,strMid,strCalc; //接收后缀表达式 //strCalc=strEndget(strEnd); //接收中缀表达式并转换 strMid=strMidget(strMid); strCalc=strTransmidend(strMid,strEnd,stackTrans); //转换为后缀表达式后完成计算 flaEndcalc(strCalc,stackCalc); fflush(stdin); getchar(); return 0; }