递归算法:四则运算表达式求解

问题描述:

输入为四则运算表达式,仅由整数、+、-、*、/、(、)组成,没有空格,要求求其值。假设运算符结果都是整数。“/”结果也是整数。

样例输入:

(2+3)*(5+7)+9/3

样例输出:

63

问题的思考及解决:

需要考虑如下几个问题:

1)计算的优先级如何实现

2)用哪一种算法的思路进行实现

3)数字与运算符混合输入,如何进行区分

我们将进行如下的考虑:

1)计算的优先级分别为:() ;* / ; 最后的是+-。如果没有()运算符,则直接进行+-*/四则运算就可以了。我们可以发现,有3层的运算优先级,且()这个运算符内可能又是一个长长的运算公式,里面可能还套个()。在这种情况下,我们不妨把问题简单化,即先考虑只有+-的运算,然后考虑+-和*/同时存在的运算,最后考虑+-*/()同时存在的运算,即我们要解决的问题。

2)解决问题的思路,就要由易向难进行处理,直接去处理3个运算顺序显得有些难度,那么我们只考虑计算+-的算式。

输入公式:11+22+33-11

输出参数:55

在最简单的问题上,我们只需要考虑如何将数据进行录入,符号如何相加减即可。在这个问题上,我们可以考虑用cin.get()和cin.peek()这2个函数,以及isdigit()判定数字的函数进行辅助。

在算法上,我们考虑定义2个函数,其中一个函数factor_value()用于读取数字并返回当前的数字,另外一个函数expression_value()用于处理+-运算。

函数factor_value()的实现思路:读取第一个字母,判断是否为数字,如果为数字,继续读取下一个字母。当前的数值为第一个数字的值*10再加上第二个数字的值,依次类推,直至读取的字母不为数字停止,返回当前读取的数字。

函数expression_value()的实现思路:通过调用factor_value()获取数字,读取下一个字母,如果为+-符号,则与下一个读取的数字进行计算。

加减运算的表达式求解代码如下:

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
int factor_value();
int expression_value();

void main()
{
	cout << "Value:" << expression_value();
}

int expression_value()
{
	int value = factor_value();
	char ch = cin.peek();
	while (true)//循环始终进行,如果不是+-数字则退出
	{
		ch = cin.get();
		if (ch == '+' || ch == '-')
		{
			if (ch == '+')
				value += factor_value();
			else 
				value -= factor_value();
		}
		else
			break;
	}
	return value;
}

int factor_value()
{
	char ch=cin.peek();
	int value = 0;
	while (isdigit(ch))
	{
		cin.get();//如果上一步循环中的peek的参数为数字,则get一下,cin指向下一个
		value = value * 10 + ch - '0';
		ch = cin.peek();//这个细节要注意,先peek一下看看,如果在while循环判断不是数字,则直接跳出
	}
	return value;
}

接着再把问题的难度上去一层,即把*/运算与+-运算一块综合起来进行考虑。

这个时候就要考虑运算符的优先程度了。如果存在*/运算,那么必然要比+-运算的优先级高,优先进行*/运算。由于同级别的顺序运算已经在上一步中完成了相关的思路梳理,这个阶段,最困难的就是如何处理+-运算与*/运算优先计算的问题,用什么方式进行处理。

在这个问题的实现上,我们仍需要再定义一个函数term_value(),这个函数用于处理*/计算。在处理优先级的问题上,我们需要考虑使用递归的思想进行处理该问题。在最简单的问题上,我们处理的字符可以划分为2类,+-运算符和数字。当出现*/时,我们同样以该思想考虑问题,即两个数字相乘的表达式,我们把这个表达式当作一个数字来处理,那么我们就可以把上面代码中,expression_value()函数中的factor_value()修改成term_value(),实现term_value()的内容与实现+-运算的方式相同。

加减运算的表达式求解代码如下:

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
int factor_value();
int term_value();
int expression_value();

void main()
{
	cout << "Value:" << expression_value();
}

int expression_value()
{
	int value = term_value();
	while (true)//循环始终进行,如果不是+-数字则退出
	{
		char ch = cin.peek();
		if (ch == '+' || ch == '-')
		{
			cin.get();
			if (ch == '+')
				value += term_value();
			else 
				value -= term_value();
		}
		else
			break;
	}
	return value;
}

int term_value()
{
	int value = factor_value();
	while (true)//循环始终进行,如果不是+-数字则退出
	{
		char ch = cin.peek();//在读取字符的部分,进行了部分修改
		if (ch == '*' || ch == '/')
		{
			cin.get();
			if (ch == '*')
				value *= factor_value();
			else
				value /= factor_value();
		}
		else
			break;
	}
	return value;
}

int factor_value()
{
	char ch=cin.peek();
	int value = 0;
	while (isdigit(ch))
	{
		cin.get();//如果上一步循环中的peek的参数为数字,则get一下,cin指向下一个
		value = value * 10 + ch - '0';
		ch = cin.peek();//这个细节要注意,先peek一下看看,如果在while循环判断不是数字,则直接跳出
	}
	return value;
}

上述代码微调了读取字母部分的代码,否则无法正常运行,因为在只有+-的代码中,函数只有1层的调用关系。而在2种不同的计算优先级代码中,需要有2层的调用关系,如果直接通过cin.get(),则会造成字符被提前调出的问题。读者在这个细节上自习研究一下,这个小细节值得细细品味

最后再把括号的计算优先级加入其中。这时会发现,括号的计算又和+-,*/这2种计算有所不同,再多一个计算,例如^求幂,则可以通过类似的方式,再多加一重函数关系即可处理该问题,但是括号与之不同点在于括号内部又是一个算式。关于括号内的算式如何进行计算,又是一个问题。我们依然把问题简化,假设括号里面是没有括号进行嵌套的。那么,括号内的算式需要进行+-*/四则运算,该运算的函数我们已经在第二个代码中写了,即调用expression_value()函数。此时,我们要考虑一个问题,是不是还需要再新建一个函数,用于判断括号。如果新建一个函数,我们会发现,其实括号的运算和数字其实是一样计算顺序,因为我们可以把括号内的算式的结果当作是数字来考虑。既然是同样的等价,那么我们把括号的判断放入函数factor_value()中进行。此时我们会发现定义的3个函数是循环调用的,且调用的终止条件为出现数字时。

最终代码:

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
int factor_value();//求一个数值或括号内的值,即因子值
int term_value();//求*/的值,即项的值
int expression_value();//求+-的值,即算式的值

void main()
{
	cout << "Value:" << expression_value();
}

int expression_value()
{
	int value = term_value();
	while (true)//循环始终进行,如果不是+-数字则退出
	{
		char ch = cin.peek();//在读取字符的部分,进行了部分修改
		if (ch == '+' || ch == '-')
		{
			cin.get();
			if (ch == '+')
				value += term_value();
			else
				value -= term_value();
		}
		else
			break;
	}
	return value;
}

int term_value()
{
	int value = factor_value();
	while (true)//循环始终进行,如果不是+-数字则退出
	{
		char ch = cin.peek();
		if (ch == '*' || ch == '/')
		{
			cin.get();
			if (ch == '*')
				value *= factor_value();
			else
				value /= factor_value();
		}
		else
			break;
	}
	return value;
}

int factor_value()
{
	char ch = cin.peek();
	int value = 0;
	if (ch == '(')
	{
		cin.get();//跳过(,取(后一个字符的值
		value = expression_value();
		cin.get();
	}
	else
	{
		while (isdigit(ch))
		{
			cin.get();//如果上一步循环中的peek的参数为数字,则get一下,cin指向下一个
			value = value * 10 + ch - '0';
			ch = cin.peek();//这个细节要注意,先peek一下看看,如果在while循环判断不是数字,则直接跳出
		}
	}
	return value;
}

 

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值