计算机软件实习1 基于逆波兰表达式的计算器制作

课前预习内容

课程要求

要求:
制作一个简单运算符计算器。
运算符包括:“+”、“-”、“*”、“/”、“(”和“)”。
可以进行多项式运算。
有一个界面展现操作过程,操作数和结果可以显示出来。

难点:
运算符带有括号,需要符号优先级判断。
需要进行多项式计算。

中缀表达式转换成后缀表达式

1.初始化两个栈:运算符栈sign和储存中间结果的栈num;
2.从左至右扫描中缀表达式;
3.遇到操作数时,将其压num;
4.遇到运算符时,比较其与sign栈顶运算符的优先级:
(1)如果sign为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
(2)否则,若优先级比栈顶运算符的高,也将运算符压入sign;
(3)否则,将sign栈顶的运算符弹出并压入到num中,再次转到(4.1)与sign中新的栈顶运算符相比较;
5.遇到括号时: 
(1)如果是左括号"(",则直接压入sign;
(2)如果是右括号")",则依次弹出sign栈顶的运算符,并压入num,直到遇到左括号为止,此时将这一对括号丢弃;
6.重复步骤2至5,直到表达式的最右边;
7.将sign中剩余的运算符依次弹出并压入num;
8.依次弹出num中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式;
在这里插入图片描述具体举例:
中缀表达式:a + b * c + ( d * e + f ) * g
后缀表达式:a b c * + d e * f + g * +

利用逆波兰表达式求值

首先,我们先来了解一下逆波兰表达式求值。
1、循环扫描语法单元的项目。
2、如果扫描的项目是操作数,则将其压入操作数堆栈,并扫描下一个项目。
3、如果扫描的项目是一个二元运算符,则对栈的顶上两个操作数执行该运算。
4、如果扫描的项目是一个一元运算符,则对栈的最顶上操作数执行该运算。
5、将运算结果重新压入堆栈。
6、重复步骤2-5,堆栈中即为结果值。
在这里插入图片描述
接着,我们了解一下运算符的优先级:
在这里插入图片描述

基于MFC制作计算器(环境VS2019)

利用MFC创建界面

  1. 创建项目:
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 计算机的界面设计
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

再完成界面的初步设计,我们需要完成相关的功能。
以字符“1”为例。
在这里插入图片描述

双击按钮“1”,出现如下界面,然后我们开始添加代码。
在头文件里定义一些需要用到的变量。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

然后是相同的操作来复制代码完成其他几个数字。
在这里插入图片描述

重点算法实现

本计算器是利用逆波兰表达式求取数值,但是在利用逆波兰表达式之前,首先需要将中缀表达式转换成后缀表达式,并给出运算符的优先级,因此,我们先设定三个函数。
在这里插入图片描述

三个函数代码具体如下:
中缀表达式转后缀表达式:

/*将表达式转换成逆波兰式*/
vector<string> CMFCApplicationDlg::toPolish(string str)
{
	stack<string> opstack;
	vector<string> polish;
	string str1;
	for (int i = 0; i < str.size(); i++)
	{
		if (str[i] == '(') /*左括号*/
		{
			opstack.push("(");
			continue;
		}
		if (str[i] >= '0' && str[i] <= '9')/*数字*/
		{
			str1 = "";
			while (i < str.size() && str[i] >= '0' && str[i] <= '9')
			{
				str1 += str[i];
				i++;
			}
			i--;
			polish.push_back(str1);
			continue;
		}

		if (str[i] == ')')/*右括号*/
		{
			/*出栈,直到匹配到左括号*/
			while (!opstack.empty())
			{
				if (opstack.top() != "(")
				{
					polish.push_back(opstack.top());
					opstack.pop();
				}
				else
				{
					opstack.pop();
					break;
				}
			}

		}
		else/*加减乘除运算符*/
		{
			str1 = str[i];
			while (!opstack.empty() && priority(opstack.top()) >= priority(str1))
			{
				polish.push_back(opstack.top());
				opstack.pop();
			}
			opstack.push(str1); // 添加到符号栈中
		}
	}
	//剩余的运算符添加到polish中
	while (!opstack.empty())
	{
		polish.push_back(opstack.top());
		opstack.pop();
	}
	return polish;
}

计算逆波兰式:

/*将逆波兰式进行计算*/
int CMFCApplicationDlg::calculate(vector<string> polish)
{
	stack<double> data;
	double a, b, c;
	for (int i = 0; i < polish.size(); i++)
	{
		if (polish[i] == "+" || polish[i] == "-" || polish[i] == "*" || polish[i] == "/")
		{
			b = data.top(); data.pop();
			a = data.top(); data.pop();
			if (polish[i] == "+") c = a + b;
			else if (polish[i] == "-") c = a - b;
			else if (polish[i] == "*") c = a * b;
			else if (polish[i] == "/") c = a / b;
			g_string.Format(_T("%d"), c);
			my_Edit.SetWindowText(g_string);
			data.push(c);
			
		}
		else
		{
			data.push(atof(const_cast<const char*>(polish[i].c_str())));/*atof函数功能:string to double */
			g_string.Format(_T("%d"), stoi(polish[i]));
			my_Edit.SetWindowText(g_string);
		}
	}
	return data.top();
}

运算符优先级:

/*返回运算符的优先级*/
int CMFCApplicationDlg::priority(string op)
{
	if (op == "(") return 0;
	if (op == "+" || op == "-") return 1;
	else if (op == "*" || op == "/") return 2;
}

有了以上三个函数,计算器的功能则可以实现,但除了计算,计算器还需具备其他功能。
其他一些操作实现如下所示:
等于号:

void CMFCApplicationDlg::OnBnClickedButton17()//=
{
	// TODO: 在此添加控件通知处理程序代码
	    std::string str= CT2A(g_string.GetString());//将全局变量转换成string类型,便于下面的函数操作
		calculate(toPolish(str));	
}

退后:

void CMFCApplicationDlg::OnBnClickedButton8()//退格
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);//将屏幕中的数据转换到变量中

	if (!g_string.IsEmpty())//如果字符串不为空
	{
		g_string = g_string.Left(g_string.GetLength() - 1);
		my_Edit.SetWindowText(g_string);
	}

	UpdateData(FALSE);//将变量中的信息显示到相应的框中
}

清空:

void CMFCApplicationDlg::OnBnClickedButton3()//清空
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	g_string = "";
	my_Edit.SetWindowText(g_string);
	UpdateData(FALSE);
}

结果输出

为了更清晰的表达计算器的运算流程,我们通过显示逻辑和处理逻辑来展示。
在这里插入图片描述

下面,我们选择一个带括号的式子进行测试:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值