表达式求值,学数据结构时的经典无问题。
以前把严蔚敏那本数据结构书上的例子都打了一遍,后来硬盘坏了就丢了,还有点小心痛,
今天学妹让我帮她写段,于是花了大半个小时就有了这一段,
首先先构思:
对于一个表达式字符串呢,机器是不认识的,所以我们要把字符串解析出来,依此的把数字放在数字栈中,符号放在符号栈中,由于老师要求不能用stack 于是就有了我自己定义的栈(只定义了计算中需要的几个函数):
<span style="font-size:18px;">template<class T>
class STACK{
private:
int p;
int msize;
T* mdate;
public:
STACK(){ //构造函数,申请栈空间
p=-1;
msize=50;
mdate= (T*)malloc(sizeof(T)*50);
}
void push(T elem){ //插入元素
if(p==msize-1){
mdate=(T*)realloc(mdate, 20*sizeof(T) );
msize += 20;
}
mdate[++p] =elem;
}
bool isempty(){ //判断栈是否为空
return p==-1;
}
void pop(){ //删除元素
if(isempty() )
exit(1);
--p;
}
T top(){ //返回栈顶元素
return mdate[p];
}
};</span>
上面就是栈的代码了 ,应为既要用到符号类型的栈,又要用到数字类型的栈,所以定义为泛型,
接下来就该是运算了:
四则运算的规则为:
- 先乘除,后加减,
- 从左到右
- 先括号内,后括号外
运算的具体过程不多说,可以参照严蔚敏的数据结构查看,
直接贴代码段,再解释一下要注意的地方吧(我假设你输入都是合法的):
char getOperation(char c, char e){ //操作表
char ope[7][7]={{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=',' '},
{'>','>','>','>',' ','>','>'},
{'<','<','<','<','<',' ','='}
};
int i,j;
if(c=='+') i=0;if(c=='-') i=1;if(c=='*') i=2;
if(c=='/') i=3;if(c=='(') i=4;if(c==')') i=5;
if(c=='#') i=6;
if(e=='+') j=0;if(e=='-') j=1;if(e=='*') j=2;
if(e=='/') j=3;if(e=='(') j=4;if(e==')') j=5;
if(e=='#') j=6;
return ope[i][j];
}
template<class T1> //读取字符串中的数字
int addunm(string str, STACK<T1> &num, int i){
int step=1;
num.push(str[i++]-'0');
while( str[i]<=57 && str[i]>=48 ){ //小数点前部分
double tmp=num.top();
num.pop();
num.push(tmp *10 + (str[i]-'0'));
i++;
step++;
}
if(str[i]=='.'){ //如有小数点继续读取
i++;
step++;
double maf= 0.1;
while( str[i]<=57 && str[i]>=48 ){
double tmp=num.top();
num.pop();
num.push(tmp+(str[i]-'0')*maf);
maf*=0.1;
i++;
step++;
}
}
return step;
}
template<class T1, class T2>
T1 getans(string str, STACK<T1> &num, STACK<T2> &op){ //计算函数
int t=str.length();
op.push('#');
int i=0;
while(i<t ){
if(isdigit(str[i])){
i+=addunm(str,num,i);
}
else{
switch (getOperation(op.top(), str[i])){
case'<':{op.push(str[i]); break;}
case'>':{
T1 tmp1 =num.top();num.pop();
T1 tmp2 =num.top();num.pop();
if(op.top() == '+' )
num.push(tmp2 + tmp1 );
if(op.top() == '-' )
num.push(tmp2 - tmp1 );
if(op.top() == '*' )
num.push(tmp2 * tmp1 );
if(op.top() == '/' )
num.push(tmp2 / tmp1 );
op.pop();
// cout<<"加:"<<num.top()<<endl;
i--;break;
}
case'=':{op.pop();break;}
case' ': {cout<<"输入表达式有误"<<endl;exit(1);}
}
i++;
}
}
return num.top();
}
应为定义的泛型,在getans函数中,返回值得类型和传人的数字栈的类型是一样的,所以就涉及到了int类型和float类型的不同,所以我把数字入栈单独出来(函数 addnum),循环读取,先读取整数位,在读取小数位,如果没有小数,小数位的读取会被忽略掉,读完后返回读取的位数(step),字符串str会往后跳step格,一直这样循环运算,直到表达式跑到尾,返回结果。
//方便伸手党给出完整的代码:
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
template<class T>
class STACK{
private:
int p;
int msize;
T* mdate;
public:
STACK(){ //构造函数,申请栈空间
p=-1;
msize=50;
mdate= (T*)malloc(sizeof(T)*50);
}
void push(T elem){ //插入元素
if(p==msize-1){
mdate=(T*)realloc(mdate, 20*sizeof(T) );
msize += 20;
}
mdate[++p] =elem;
}
bool isempty(){ //判断栈是否为空
return p==-1;
}
void pop(){ //删除元素
if(isempty() )
exit(1);
--p;
}
T top(){ //返回栈顶元素
return mdate[p];
}
};
char getOperation(char c, char e){ //操作表
char ope[7][7]={{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},
{'>','>','>','>','<','>','>'},
{'<','<','<','<','<','=',' '},
{'>','>','>','>',' ','>','>'},
{'<','<','<','<','<',' ','='}
};
int i,j;
if(c=='+') i=0;if(c=='-') i=1;if(c=='*') i=2;
if(c=='/') i=3;if(c=='(') i=4;if(c==')') i=5;
if(c=='#') i=6;
if(e=='+') j=0;if(e=='-') j=1;if(e=='*') j=2;
if(e=='/') j=3;if(e=='(') j=4;if(e==')') j=5;
if(e=='#') j=6;
return ope[i][j];
}
template<class T1> //读取字符串中的数字
int addunm(string str, STACK<T1> &num, int i){
int step=1;
num.push(str[i++]-'0');
while( str[i]<=57 && str[i]>=48 ){ //小数点前部分
double tmp=num.top();
num.pop();
num.push(tmp *10 + (str[i]-'0'));
i++;
step++;
}
if(str[i]=='.'){ //如有小数点继续读取
i++;
step++;
double maf= 0.1;
while( str[i]<=57 && str[i]>=48 ){
double tmp=num.top();
num.pop();
num.push(tmp+(str[i]-'0')*maf);
maf*=0.1;
i++;
step++;
}
}
return step;
}
template<class T1, class T2>
T1 getans(string str, STACK<T1> &num, STACK<T2> &op){ //计算函数
int t=str.length();
op.push('#');
int i=0;
while(i<t ){
if(isdigit(str[i])){
i+=addunm(str,num,i);
}
else{
switch (getOperation(op.top(), str[i])){
case'<':{op.push(str[i]); break;}
case'>':{
T1 tmp1 =num.top();num.pop();
T1 tmp2 =num.top();num.pop();
if(op.top() == '+' )
num.push(tmp2 + tmp1 );
if(op.top() == '-' )
num.push(tmp2 - tmp1 );
if(op.top() == '*' )
num.push(tmp2 * tmp1 );
if(op.top() == '/' )
num.push(tmp2 / tmp1 );
op.pop();
// cout<<"加:"<<num.top()<<endl;
i--;break;
}
case'=':{op.pop();break;}
case' ': {cout<<"输入表达式有误"<<endl;exit(1);}
}
i++;
}
}
return num.top();
}
int main(){
STACK<char> op ; //复函栈
STACK<double> num ; //数字栈
string Expression; //表达式
cout<<"输入表达式(以#结尾如:1+2+3+4#):";
cin>>Expression;
//此处ans的数据类型请和数据栈的数据类型保持一致
//计算时会自动匹配
double ans=getans(Expression, num, op);
cout<<ans <<endl;
return 0;
}