计算器(表达式计算-后缀表达式实现)

计算器(表达式计算-后缀表达式实现)

【问题描述】

从标准输入中读入一个整数算术运算表达式,如24 / ( 1 + 2 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 )= ,计算表达式结果,并输出。

要求:

1、表达式运算符只有+、-、*、/,表达式末尾的=字符表示表达式输入结束,表达式中可能会出现空格;
2、表达式中会出现圆括号,括号可能嵌套,不会出现错误的表达式;
3、出现除号/时,以整数相除进行运算,结果仍为整数,例如:5/3结果应为1。
4、要求采用逆波兰表达式来实现表达式计算。

【输入形式】

从键盘输入一个以=结尾的整数算术运算表达式。操作符和操作数之间可以有空格分隔。

【输出形式】

在屏幕上输出计算结果(为整数,即在计算过程中除法为整除)。

【样例输入】

24 / ( 1 + 2 + 36 / 6 / 2 - 2) * ( 12 / 2 / 2 )     =

【样例输出】

18

【样例说明】

按照运算符及括号优先级依次计算表达式的值。

【评分标准】

通过所有测试点得满分。

分析

  • 本题考查使用逆波兰式实现简单计算器的功能。(逆波兰表达式
  • 由于输入是中缀表达式,因此要先将中缀表达式转化为后缀表达式。具体规则可以参考前一条的两个超链接的资料,或者参考视频动画:中缀转后缀。(PS:个人认为本题的最大难点就是在于这个步骤,这个步骤可能算不上特别难,但是里面有许多小细节需要注意,不然会导致转换错误
  • 转换中缀表达式过程中,需要将运算符存入栈中,这需要先对字符的优先级进行比较,由于运算符较多,因此我设置了一个函数,给操作符设置了一个整型的优先级,以便于进行对比。
  • 将中缀表达式转换为后缀表达式以后,问题就变得较为容易,可以按照逆波兰表达式的计算规则对表达式进行处理,最终可以得到运算结果。
  • 由于对逆波兰表达式进行计算时还需要将操作数存入栈中,我个人觉得太啰嗦就通过数组实现了一个‘假栈’来储存操作数。(本题两次用到栈,且存储的数据的类型不同,一个是字符型一个是整型,由于水平有限,我无法实现栈的复用,就采取了这样的方式)

代码

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

typedef struct Stack* S;
typedef char type;

struct Stack
{
	type data[100];
	int pos;
};
//创建并初始化堆栈
S init()
{
	S s;
	s = (S)malloc(sizeof(struct Stack));
	s->pos = -1;
	return s;
}
//判断栈是否为空
int empty(S s)
{
	if (s->pos == -1)
		return 1;
	return 0;
}
//压栈
int push(S s, type x)
{
	s->pos += 1;
	s->data[s->pos] = x;
	return 0;
}
//弹栈
type pop(S s)
{
	s->pos -= 1;
	return s->data[s->pos + 1];
}
//获得运算符的优先级
int getgrade(char c)
{
	if (c == '(')
		return 1;    //由于栈顶为左括号时符号可直接压栈,因此将其等级设为最低
	if (c == '+' || c == '-')
		return 2;
	if (c == '*' || c == '/')
		return 3;
}
//主函数
int main()
{
	char str[100] = { '\0' }, fin_str[100] = { '\0' };  //储存初始字符串、逆波兰式
	int operand[100] = { 0 }, i = 0, j = 0, pos_ope = -1;
	S s = init();
	gets_s(str);
	while (str[i] != '=') {
		if (str[i] == ' '){   //空格不处理
			i++;
			continue;
		}
		if (str[i] >= '1' && str[i] <= '9') {   //数字直接添加到逆波兰表达式,通过逗号分隔
			while (str[i] >= '0' && str[i] <= '9') {
				fin_str[j++] = str[i++];
			}
			fin_str[j++] = ',';
			continue;
		}
		else if (empty(s) || str[i] == '(') {   //空栈或者栈顶为左括号时直接将运算符压栈
			push(s, str[i++]);
			continue;
		}
		char c = pop(s);
		if (str[i] == ')') {   //运算符为右括号时,开始弹栈,直到弹出左括号
			while (c != '(') {
				fin_str[j++] = c;
				fin_str[j++] = ',';
				c = pop(s); 
			}
			i++;
		}
		else {   //栈顶与当前字符都是普通运算符时,如果当前字符优先级小,则弹栈,直到其比栈顶元素优先级高,再压栈
			while (getgrade(c) >= getgrade(str[i])) {
				fin_str[j++] = c;
				fin_str[j++] = ',';
				if (empty(s))  //若把栈弹空,则跳出循环
					break;
				c = pop(s);
			}
			if (getgrade(c) < getgrade(str[i])) {  //若由于弹出的栈顶元素优先级小于当前字符而跳出上方循环,则应将其再压栈
				push(s, c);
				push(s, str[i++]);
			}
		}
	}
	while (!empty(s)) {   //处理完字符串,应将栈内剩余所有运算符都添加到逆波兰表达式
		fin_str[j++] = pop(s);
		fin_str[j++] = ',';
	}
	
	i = 0;
	while (i<strlen(fin_str)) {
		if (fin_str[i] == ','){ //解析逆波兰表达式,作为分隔符的逗号不解析
			i++;
			continue;
		}
		char c = fin_str[i];
		if (c == '+' || c == '-' || c == '*' || c == '/') {   //如果是运算符,就在操作数栈中弹出两个元素进行相应运算
			int b = operand[pos_ope--], a = operand[pos_ope--], res;
			switch (c){
				case '+':res = a + b; break;
				case '-':res = a - b; break;
				case '*':res = a * b; break;
				case '/':res = a / b; break;
			}
			operand[++pos_ope] = res;   //将运算结果重新压入运算符栈
			i++;
		}
		else{  //解析到数字时,将其由字符串形式转为整数,压入操作数栈
			char ope[5] = { '\0' };
			j = 0;
			while (fin_str[i] >= '0' && fin_str[i] <= '9') {
				ope[j++] = fin_str[i++];
			}
			int res = atoi(ope);   //stdlib.h自带函数,将数字字符串转为整数
			operand[++pos_ope] = res;
		}
	}
	printf("%d\n", operand[0]);   //操作数栈内最终剩下的元素即运算结果
	return 0;
}
  • 9
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谛凌

本人水平有限,感谢您支持与指正

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值