C/C++语言:简单计算器、中缀式求值问题

问题描述:

 这里的算数运算求值问题是:用户输入包含运算符“+”,“-”,“*”,“/”,“(”,“)”及正整数构成的合法算数运算式(即中缀式)例如:4+(2*5-6/12),计算并输出该表达式的运算结果。

问题分析:

 这是数据结构中堆栈的经典应用,考察栈的基本操作,及一些多分枝结构的代码编写,同时还涉及到表达式中运算符的一些逻辑问题。

 这里需要先定义两个栈,一个运算符栈op,一个运算数栈num,在代码中直接使用C/C++的标准库函数来声明(就可不用管栈的具体操作,减少代码量),就需要添加头文件及标准命名空间:

#include<stack>
using namespace std;

 在看代码之前,需要先定义运算符的优先级(平时口算时其实也是遵循了“从左到右,先乘除后加减,先括号里后括号外的优先原则”,这里只是把其量化)。同时运算符要区分左右,因为会比较   当前扫描到的运算符(即右运算符)  与  运算符栈顶的运算符(即左运算符) 的优先级孰高孰低

运算符优先级
运算符=(+-*/)
左运算符0133556
右运算符0622441
说明等于左括号右括号
伪代码:

//初始化运算符栈op、运算数栈num;
//将“=”入运算数符(这只是为了方便操作);
//黑框输入一个中缀式子;
/*以下循环逐个扫描输入的中缀式 */

/*while(中缀式未扫描完)
{
	if(当前扫描字符为操作符)
	{
		if(当前扫描操作符 优先级 大于 op栈顶元素 优先级) 
			当前操作符入栈op;
			读取下一个字符;
		else if(当前扫描操作符 优先级 等于 op栈顶元素 优先级)
			退op栈顶元素(其实这种情况只有可能是右括号遇到左括号)
		else 小于
			运算数栈num连续出两个元素,运算符栈op出栈顶元素,进行相应运算;
			运算结果再入运算数栈num;
	}
	else   当前扫描的字符为数字
		数字直接入运算数栈num;
}
扫描完毕,输出结果;


*/

直接看代码吧:

#include<stdio.h>
#include<stack>

using namespace std;
#define MaxOp 7											//操作符的个数

struct                                                  //运算符优先级结构体
{
	char cu_opchar;
	int priority;
}left_priority[]={{'=',0},{'(',1},{'+',3},{'-',3},{'*',5},{'/',5},{')',6}},
right_priority[]={{'=',0},{'(',6},{'+',2},{'-',2},{'*',4},{'/',4},{')',1}};

bool IsOperatorChar(char  ch)							//判断是运算符还是数字
{
	if(ch=='('||ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch==')')
		return true;
	else return false;
}

int Get_LeftPriority(char cu_opchar)					//求左运算符优先级
{
	for (int i = 0; i < MaxOp; i++)
		if (left_priority[i].cu_opchar == cu_opchar) return left_priority[i].priority;
}

int Get_RightPriority(char cu_opchar)					//求右运算符优先级
{
	for (int i = 0; i < MaxOp; i++)
		if (right_priority[i].cu_opchar == cu_opchar) return right_priority[i].priority;
}			//

int JudgePriority(char left_ch,char right_ch)			//判左右优先级高级
{
	int left_p = Get_LeftPriority(left_ch);
	int right_p = Get_RightPriority(right_ch);
	if (left_p < right_p) return -1;
	else if(left_p == right_p) return 0;
	else return 1;
}	 

float Calculator(float first_num,float second_num,char tmp_ch)	//计算逻辑
{
	float sum;
	switch (tmp_ch)
	{
		case '+': sum = first_num+second_num;
			break;
		case '-': sum = first_num-second_num;
			break;
		case '*': sum = first_num*second_num;
			break;
		case '/': 
			if (second_num==0)
			{
				printf("错误:除数为0!\n");exit(0);
			}
			sum = first_num/second_num;
			break;
		default: printf("错误:无效的表达式!\n");exit(0);
			break;
	}
	return sum;

}

int main()
{
	stack<char> op;										//运算符栈
	stack<float> num;									//运算数栈

	int cu_char_no;
	float first_num,second_num,sum;
	float tmp_num;
	char cu_char;
	char op_topch;
	char in_str[201];
	char tmp_ch;

	while (scanf("%s",in_str)!=EOF)
	{
		
		//清空操作符栈和数字栈
		while (!op.empty()) op.pop();
		while (!num.empty()) num.pop();
		cu_char_no =0;
		//将“=”入操作符栈
		op.push('=');
		//while挨个从输入读取字符,直至输入字符串读取完毕
		while (in_str[cu_char_no]!='\0')
		{
			cu_char =in_str[cu_char_no];

			//若当前字符为操作符
			if (IsOperatorChar(cu_char))
			{
				int p = JudgePriority(op.top(),cu_char);
				switch (p)
				{	
					case -1:					//当前字符优先级大于操作符栈顶元素的优先级,
						op.push(cu_char);		//当前符入栈
						cu_char_no++;			//!!!读取下一个字符
						break;
					case 0:						//当前优先级等于栈顶(只有左括号遇到右括号情况)
						op.pop();				//操作符栈退栈顶元素 
						cu_char_no++;			//!!!读取下一个字符
						break;
					default:					//(当前优先级小于栈顶元素)
						tmp_ch = op.top();		//操作符栈顶元素出栈,数字栈出两元素进行运算
						op.pop();
						first_num= num.top();num.pop();
						second_num= num.top();num.pop();
						sum= Calculator(second_num,first_num,tmp_ch);
						num.push(sum);			//结果入数字栈
					break;
				}					
			}
			//当前字符为数字
			else
			{
				tmp_num = 0;
				tmp_ch =in_str[cu_char_no];
				while (tmp_ch>='0'&&tmp_ch<='9')
				{
					tmp_num=tmp_num*10 +tmp_ch-'0';
					tmp_ch =in_str[++cu_char_no];
				}
				//数字处理,结果入数字栈	
				num.push(tmp_num);
			}
		}
		//处理完毕,输出结果
		while (!op.empty())
		{
			tmp_ch = op.top();op.pop();
			if (tmp_ch == '=')
			{
				printf("计算结果为:%.2f\n",num.top());break;
			}
			else
			{
				first_num= num.top();num.pop();
				second_num= num.top();num.pop();
				sum= Calculator(second_num,first_num,tmp_ch);
				num.push(sum);			//结果入数字栈
			}
		}

	}
	return 0;
}

黑框框输入及输出:


后记:

写一写的就写了小150行的代码,代码还比较啰嗦。以上算法及思路参考了李春葆的《数据结构教材》第四版,但他是把

中缀式先转化成后缀式,然后再用后缀式计算结果的。

while (scanf("%s",in_str)!=EOF)
 上面这句在ACM中见的比较多,是用于多次进行输入待处理数据的。
tmp_num = 0;
tmp_ch =in_str[cu_char_no];
//数字处理,
while (tmp_ch>='0'&&tmp_ch<='9')
{
	tmp_num=tmp_num*10 +tmp_ch-'0';
	tmp_ch =in_str[++cu_char_no];
}
//结果入数字栈	
num.push(tmp_num);
 上面的while循环是用于将chan类型的任意位的数字字符转换成float(或者是int)的数字


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值