Bootstrap

【数据结构】顺序栈 表达式求值 ---C语言实现

题目:设计一个模拟计算器的程序,要求能对包含加、减、乘、除、括号运算符及sqrt和abs函数的任意整数型表达式进行求解。(难易度90)
要求:要检查有关运算的条件,并对可能的错误产生报警。
实现效果:
在这里插入图片描述
在这里插入图片描述

实现:
两个顺序栈
扫描到数字:用j标记,实现多位数的情况运算完后再入栈
扫描到符号:符号栈为空,入栈
符号栈有操作符,比较优先级,新的运算符比栈顶运算符优先级高,进行运算,优先级低,运算符入栈,优先级相等,运算符出栈

小细节

负数的实现:起始位为“-”号,补0,左括号后紧接着“-”号,补0
用A代替abs绝对值函数
用S代替sqrt开平方根函数(不区分大小写)

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<stdbool.h>

#define MAX 1000
//数据栈
typedef struct NumStack{
	double nums[MAX];
	int top;
}NumStack;
//运算符栈
typedef struct OpStack{
	char ops[MAX];
	int top;
}OpStack;

//初始化
void init_Nums(NumStack *s){
	s->top = -1;
}
void init_Ops(OpStack *s){
	s->top = -1;
}

//入栈
bool push_Nums(NumStack *s,double val){
	if(s->top == MAX-1){
		printf("数据栈满\n");
		exit(-1);
	}
	s->top++;
	s->nums[s->top] = val;
	return true;
}
bool push_Ops(OpStack *s,char ch){
	if(s->top == MAX-1){
		printf("运算符栈满\n");
		exit(-1);
	}
	s->top++;
	s->ops[s->top] = ch;
	return true;
}

//出栈
bool pop_Nums(NumStack *s){
	if(s->top == -1){
		printf("数据栈空\n");
		exit(-1);
	}
	s->top--;
	return true;
}
bool pop_Ops(OpStack *s){
	if(s->top == -1){
		printf("运算符栈空\n");
		exit(-1);
	}
	s->top--;
	return true;
}

//取栈顶
double head_Nums(NumStack *s){
	if(s->top == -1){
		printf("数据栈空\n");
		exit(-1);
	}
	return s->nums[s->top];
}
char head_Ops(OpStack *s){
	if(s->top == -1){
		printf("运算符栈空\n");
		exit(-1);
	}
	return s->ops[s->top];
}

//运算
double calculate(double a,double b,char op){
	double s = 0.0;
	switch(op){
		case '+': s = a+b; break;
		case '-': s = a-b; break;
		case '*': s = a*b; break;
		case '/': 
			if(b == 0){
				printf("ERROR:除数不能为0!\n");
				exit(-1);
			}else{
				s = a/b;
			}
			break;
		case 'A':case 'a': s = fabs(b); break;
		case 'S':case 's': 
			if(b < 0){
				printf("ERROR:平方根不能为负!\n");
				exit(-1);
			}else{
				s = sqrt(b);
			}
			break;
	}
	printf("%.2lf %c %.2lf = %.2lf\n",a,op,b,s);
	return s;
}
//判断运算符优先级
char Compare(char op1,char op2){
	char tab[9][10] = {
		{'>','>','<','<','<','>','<','<','>'},
		{'>','>','<','<','<','>','<','<','>'},
		{'>','>','>','>','<','>','<','<','>'},
		{'>','>','>','>','<','>','<','<','>'},
		{'<','<','<','<','<','=','<','<','E'},
		{'>','>','>','>','E','>','>','>','>'},
		{'>','>','>','>','<','>','>','>','>'},
		{'>','>','>','>','<','>','>','>','>'},
		{'<','<','<','<','<','E','<','<','='}
	};
	char op[10] = {'+','-','*','/','(',')','A','S','#'};
	int x = 0,y = 0;
	for(int i = 0;i<9;i++){
		if(op[i] == op1) x = i;
		if(op[i] == op2) y = i;
	}
	if(tab[x][y] == 'E'){
		printf("输入表达式错误");
		exit(-1);
	}
	return tab[x][y];
}
//检查表达式输入是否合法
bool check(char *s,int len){
	int i = 0;
	for(i;i<len;i++){
		if(s[i]>='0' && s[i]<='9') continue;
		if(s[i]=='(' || s[i]==')' || s[i]=='+' || s[i]=='-' || s[i]=='*' || s[i]=='/' || s[i]=='A' || s[i]=='a' || s[i]=='S' || s[i]=='s' || s[i]=='.') continue;
		return false;
	}
	return true;
}

void changeCase(char *op){
	if(*op == 'a')
		*op = 'A';
	if(*op == 's')
		*op = 'S';
}

int main(int argc, const char* argv[])
{
	char expre[100],num[100];
	int len;
	NumStack nstack;
	OpStack ostack;
	init_Nums(&nstack);
	init_Ops(&ostack);
	push_Ops(&ostack,'#');
	printf("请输入表达式:\n");
	scanf("%s",expre);
	len = strlen(expre);
	if(!check(expre,len)){
		printf("输入的表达式不合法!\n");
		exit(-1);
	}
	int i=0,j=0,k=0;
	double x=0,y=0,temp = 0;
	expre[len] = '#';
	//起始为负数的情况
	if(expre[0] == '-'){
		push_Nums(&nstack,0);
	}
	for(i;i<=len;i++){
		changeCase(&expre[i]);
		if(expre[i]>='0' && expre[i]<='9' || expre[i]=='.'){
			temp = temp*10+(expre[i]-48);//多位数
			j = 1;
			continue;
		}
		if(j){
			push_Nums(&nstack,temp);
			j=0;
			temp = 0;
		}
		//左括号后紧接着是-号的是负数
		if(expre[i]=='(' && expre[i+1]=='-'){
			num[i+1] = 0;
			push_Nums(&nstack,0);
		}
		switch(Compare(head_Ops(&ostack),expre[i])){
			case '<':
				push_Ops(&ostack,expre[i]);
				break;
			case '=':
				pop_Ops(&ostack);
				break;
			case '>':
				//abs和sqrt只需要出一个数据
				if(head_Ops(&ostack)== 'A' || head_Ops(&ostack)== 'S'){
					y = head_Nums(&nstack);
					pop_Nums(&nstack);
					push_Nums(&nstack,calculate(0,y,head_Ops(&ostack)));
				}else{
					y = head_Nums(&nstack);
					pop_Nums(&nstack);
					x = head_Nums(&nstack);
					pop_Nums(&nstack);
					push_Nums(&nstack,calculate(x,y,head_Ops(&ostack)));	
				}
				pop_Ops(&ostack);
				i--;
				break;
		}
	}
	double result = head_Nums(&nstack);
	printf("该表达式的结果为:%.2lf",result);
	return 0;
}

存在的问题:如果运算符在后,也可以进行运算,按正常情况应该报错,但是仍然进行运算了
在这里插入图片描述

;