利用栈求表达式的值(数据结构课程设计)

课程设计的内容和要求(包括原始数据、技术要求、工作要求等)

编写程序实现表达式求值,即验证某算术表达式的正确性,若正确,则计算该算术表达式的值。

主要功能描述如下:

1、从键盘上输入表达式。

2、分析该表达式是否合法:

(1)是数字,则判断该数字的合法性。若合法,则压入数据到堆栈中。

(2)是规定的运算符,则根据规则进行处理。在处理过程中,将计算该表达式的值。

(3)若是其它字符,则返回错误信息。


运算符优先级

对于连个相继出现的操作符θ1和θ有三种关系:大于、等于和小于。由此可以列出“+-*/”之间的优先级。如下表:

  + - * / ( ) #
+ > > < < < > >
- > > < < < > >
* > > > > < > >
/ > > > > < > >
( < < < < < =  
) > > > >   > >
# < < < < <   =

 

加减乘除优先性都低于“(”但是高于“)”,由运算从左到右可知,当θ12 ,令θ12

为了算法简洁,在表达式的左边和右边虚设一个“#”,这一对“#”表示一个表达式求值完成。

“(”=“)”当一对括号相遇时表示括号内已运算完成。

“)”和“(”、“#”和“(”、“(”和“#”无法相继出现如果出现则表达式出现语法错误。

为实现优先算法,可以使用两个工作栈,一个是OPTR,用于寄存运算符,一个是OPND,用于寄存运算数和运算结果。

算法基本思路。

首先置操作数栈为空栈,表达式起始符为“#”为栈底元素。

依次读入表达式中的每个字符,若是操作数则进OPND栈,若是运算符则和OPTR栈的栈顶运算符比较优先权作相应操作,直至整个表达式求值完毕(OPTR栈顶元素和当前读入的字符均为“#”)



#include
#include
#include
#include
#include
using namespace std;
stackopnd;  //存储运算数 
stackoptr;  //存储运算符 
char pre; //记录当前字符的前一个字符,用于负数的判断 
int flag ; //值=1表示为负数,否则为正数 

void init(){  //初始化 
	optr.push('#');
	pre = '#';
	flag = 0;
}

int IsNumber(char c){  //检查是否是数字 
	if(c >= '0' && c <= '9')return 1;
	return 0;
}


int ErrorCheck(char c){  //返回1表示不是规定运算符 
   if(c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' || c == '#')return 0;
   return 1;
}


char Precede(char f,char l){   //运算级判断 
	if(f == '+' || f == '-'){
		if(l == '*' || l == '/' || l == '(') return '<';
		else return '>';
	}
	if(f == '*' || f == '/'){
		if(l == '(') return '<';
		else return '>';
	}
	if(f == '('){
		if(l == ')') return '=';
		else if(l!='#')return '<';
	} 
	if(f ==')' && l !='(') return '>';
	if(f == '#'){
		if(l == '#') return '=';
		else if(l!=')')return '<';
	} 
	
	return '0';
}

double Compute(double b,char oper,double a){
	if(oper == '-') return a-b;
	if(oper == '+') return a+b;
	if(oper == '*') return a*b;
	if(oper == '/') return a/b;
}

int main(){
	init();
	char ch = getchar();
	while(ch != '#' || optr.top() != '#'){
		if(IsNumber(ch)){
            double tot = 0;
            do{
            tot *= 10;
            tot += (ch - '0');
            pre = ch;
            ch = getchar();
			}while(IsNumber(ch));
			
			if(ch == '.'){  //小数点后的数值 
				ch = getchar();
				double tmp = 0.1;
				while(IsNumber(ch)){
					tot += (ch - '0')*tmp;
					tmp *= 0.1;
					pre = ch;
					ch = getchar();
				}
			}
			if(flag){
				tot = 0 - tot;
				flag = 0;
			}
			opnd.push(tot);
		}else if(ch == '-' && (pre == '#' || pre == '(')){   //负数的判定
			flag = 1;
			ch = getchar();
		}else {
		  if(ErrorCheck(ch)) {
		  	printf("存在非规定的运算字符!\n"); 
		  	return 0;
		  }
		  
		  
		  switch(Precede(optr.top(),ch)){
		  	 case '<' :{     //栈顶运算符优先级小 
		  	 	optr.push(ch);
		  	 	pre = ch;
		  	 	ch = getchar();  //重新接收下一个字符 
				break;
			   }
		     case '=' :{
		     	optr.pop(); //出栈一对括号
		     	pre = ch;
				ch = getchar(); //重新接收下一个字符 
				break;
			   }
			 case '>' :{
			 	char oper = optr.top(); 
				optr.pop();  //出栈一个运算符 
			 	double a = opnd.top(); opnd.pop();
				double b = opnd.top(); opnd.pop();  //出栈两个操作数 
				
				double tot = Compute(a,oper,b);  //计算值,并将结果压入堆栈
				opnd.push(tot); 
				break;
			 } 
			 case '0':{
		  	 printf("表达式语法错误,括号不匹配!\n");
		  	 return 0;			 	
				break;
			 }
		  } //switch
		}  //else
	} //while
	
	printf("%.2lf\n",opnd.top());
	opnd.pop();
	return 0;
} 


输入形式如:2+(-2+10)*5/2#    以#号结尾


你可能感兴趣的:(堆栈)