首页 > 编程语言 >结对项目:用C++实现四则运算

结对项目:用C++实现四则运算

时间:2023-09-28 23:12:00浏览次数:40  
标签:std 结对 压入 opr 四则运算 C++ num 操作符 stack

软工作业3:自动生成小学四则运算题目的命令行程序

这个作业属于哪个课程 计科21级1 2班
这个作业要求在哪里 结对项目
这个作业的目标 熟悉合作开发流程
项目Github 点击这里
团队成员
姓名 学号
石云欣 3221004809
沈纪康 3121004750

PSP表

PSP2.1 Personal Software Process 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 10
· Estimate · 估计这个任务需要多少时间 20 10
Development 开发 880 840
· Analysis · 需求分析 (包括学习新技术) 220 250
· Design Spec · 生成设计文档 50 30
· Design Review · 设计复审 30 20
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 25
· Design · 具体设计 50 30
· Coding · 具体编码 200 205
· Code Review · 代码复审 80 40
· Test · 测试(自我测试,修改代码,提交修改) 100 150
Reporting 报告 90 90
· Test Report · 测试报告 20 20
· Size Measurement · 计算工作量 20 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 50 60
· 合计 990 940

运行环境

VisualStudio 2022

效能分析

程序中耗时最长的函数为 Generation:: IOsystem ,该函数集成了生成算式与存储至对应文件两个功能,主要性能瓶颈在于生成随机数与判断算式是否符合规范,即计算过程中不出现负数。

void Generation::IOsystem()
{
	Arithmetics A;
	std::ofstream outFile("exercisefile.txt");
	std::ofstream outFile_answer("Answer.txt");
	if (!outFile) {
		std::cerr << "无法打开输出文件." << std::endl;
		return;
	}
	if (!outFile_answer) {
		std::cerr << "无法打开输出文件." << std::endl;
		return;
	}
	for (int i = 0; i < request; i++){
		std::vector<int>numList = NumGeneration(numLimit);
		std::vector<char>operaList = OperatorGeneration();
		std::string expression = Combination(numList, operaList);
		if (expression.size()>3){
			std::random_device rd;
			std::mt19937 gen(rd());
			std::uniform_int_distribution<int> dist(0, 1);
			int isParentheses = dist(gen); // 随机生成 0 或 1
			if (isParentheses == 1){
				std::random_device rd;
				std::mt19937 gen(rd());
				std::uniform_int_distribution<int> dist(0, 3);
				int parenthesesPosition = dist(gen) * 2;
				while (parenthesesPosition > expression.size() - 2)
				{
					parenthesesPosition = parenthesesPosition - 2;
				}
				expression.insert(parenthesesPosition,1, '(');
				expression.insert(parenthesesPosition + 4, 1, ')');
			}
		}
		A.string_without_space_to_equation(expression);
		std::string res = A.get_result().to_string();
		if (A.get_result().numerator > 729||A.get_result().denominator>729) {
			i--;
			A.clear();
			continue;
		}
		outFile << i + 1 << ". " << expression << "\n";
		outFile_answer << i + 1 << ". " << res << "\n";
		A.clear();
	}
	outFile.close();
	outFile_answer.close();
}

改进方案

  1. 批量生成随机数:批量生成一些随机数,然后在循环中使用这些随机数。这可以减少生成器调用的次数。
  2. 多线程生成:使用多线程来并行生成随机数以提高生成的效率。
  3. 硬件随机数生成器:计算机系统提供的硬件随机数生成器速度更快。

设计实现过程

四则运算的实现原理为使用后缀表达式对算式进行求解。

在类Arithmetic中内置了三个函数

void string_to_equation(std::string str);
void string_with_space_to_equation(std::string str);
void string_without_space_to_equation(std::string str);

用来实现将字符串格式的算式直接转换为Arithmetic类型,即将数字与算术符分别存入成员 std::vector<Number> nums std::vector<Operator> operators以进行下一步操作。

  1. 初始化一个操作符栈 opr_stack 和一个结果栈 num_stack
  2. 从左到右遍历中缀表达式的每个字符:
    • 如果是操作数(数字),直接压入结果栈 num_stack
    • 如果是操作符:
      1. 检查操作符栈 opr_stack 的栈顶元素,如果栈顶操作符的优先级高于或等于当前操作符的优先级,并且栈顶元素不是左括号,就将栈顶操作符弹出并压入结果栈,直到不满足条件。
      2. 将当前操作符压入操作符栈 opr_stack
    • 如果是左括号 (,将其压入操作符栈 opr_stack
    • 如果是右括号 ),执行以下步骤:
      1. 从操作符栈 opr_stack 中弹出元素并压入结果栈,直到遇到左括号 (,但不要将左括号压入结果栈。
      2. 弹出左括号 (,但不压入结果栈。
  3. 遍历完成后,将操作符栈中的所有剩余操作符弹出并压入结果栈。
  4. 最终,结果栈 num_stack 中的元素就是后缀表达式。

计算后缀表达式的过程(以3 4 + 5 *为例) 过程如下:

  1. 从左到右扫描表达式。
  2. 遇到算数符时,将其推入栈中。
  3. 遇到运算符时,从栈中弹出相应数量的操作数进行运算,然后将结果推回栈中。
  4. 最终,栈中的唯一元素就是表达式的结果。

在上述示例中,计算过程如下:

  • 遇到 3,将其推入栈中:栈 [3]
  • 遇到 4,将其推入栈中:栈 [3, 4]
  • 遇到 +,从栈中弹出两个操作数 34,计算结果 7,将结果推回栈中:栈 [7]
  • 遇到 5,将其推入栈中:栈 [7, 5]
  • 遇到 *,从栈中弹出两个操作数 75,计算结果 35,将结果推回栈中:栈 [35]

最终,栈中的元素 35 就是表达式 3 4 + 5 * 的计算结果。

主函数流程图如下:

代码说明

Arithmetics::calculate

Number Arithmetics::calculate()
{
	if (nums.empty()) return Number{ 0 };
	auto it_num = nums.begin();
	auto it_opr = operators.begin();
	std::stack<Number> num_stack;
	std::stack<Operator> opr_stack;

	while (it_num != nums.end())
	{
		if (it_opr != operators.end() && it_opr->get_type() == LeftBrace)
		{
			num_stack.push(calculate_in_brace(it_num, ++it_opr));
		}
		else
		{
			if (it_num == nums.end()) break;
			num_stack.push(*it_num);
			++it_num;
		}

		if (it_opr == operators.end()) break;

		// if the operator stack is not empty and next operator's priority is less equal than previous operator's
		while (!opr_stack.empty() && it_opr->get_priority() <= opr_stack.top().get_priority())
		{
			Number& b = num_stack.top();
			num_stack.pop();
			Number& a = num_stack.top();
			num_stack.pop();

			num_stack.push(opr_stack.top().func(a, b));
			opr_stack.pop();
		}

		opr_stack.push(*it_opr);
		++it_opr;
	}
	if (num_stack.empty())
	{
		std::cerr << "ERROR : Empty result";
		return Number{ 0, 0 };
	}
	while (!opr_stack.empty())
	{
		Number& b = num_stack.top();
		num_stack.pop();
		Number& a = num_stack.top();
		num_stack.pop();

		num_stack.push(opr_stack.top().func(a, b));
		opr_stack.pop();
	}
	return num_stack.top();
}

​ 这段代码的目标是实现一个数学表达式的计算器,它通过遍历表达式中的数值和运算符,使用两个栈(num_stack 和 opr_stack)来帮助我们完成计算。

​ 代码的工作原理如下:

  1. 我们将数值压入 num_stack,将运算符压入 opr_stack。
  2. 当遇到左括号时,我们会调用 calculate_in_brace 函数来计算括号内的表达式,并将结果压入 num_stack。
  3. 当遇到右括号或者运算符优先级低于 opr_stack 栈顶运算符的优先级时,我们会从 num_stack 弹出两个数值和 opr_stack 弹出一个运算符,然后进行相应的运算,并将结果压入 num_stack。我们会一直重复这个过程,直到 opr_stack 为空或者遇到左括号。
  4. 最后,如果我们已经遍历完了 nums 和 operators,但 opr_stack 仍然不为空,那么我们会继续弹出 num_stack 的两个数值和 opr_stack 的一个运算符,进行相应的运算,并将结果压入 num_stack。这个过程会一直重复,直到 opr_stack 为空。
  5. 最终,num_stack 的栈顶元素就是整个表达式的计算结果,将其返回。

测试代码

控制台输入如下:

exercisefile.txt所存储的生成题目如下:

Answer.txt所存储的答案如下:

用户输入答案至answerfile.txt如下(将第十题答案修改为错误的值后):

成绩输入至Grade.txt如下:

项目小结

经验:

  • 密切的合作: 每天都保持沟通,确保项目进展顺利。
  • 技能互补: 拥有不同的技能和背景,我们能够相互补充,提供更全面的解决方案。
  • 任务分工明确: 减少重复工作和提高效率。

教训和挑战:

  • 时间管理: 在项目初期我们没有提前规划时间,导致项目的开工时间一再推迟。
  • 沟通障碍: 缺少面对面沟通,很多时候聊了半天才发现说的不是同一个模块。
  • 技术难题: 在生成算式的模块上,花费了较多时间。

结对感受:
我们在项目中面对了许多挑战,但通过相互的协作和努力,我们克服了这些问题,从中学到了很多。这个合作经验也让我更好地理解了团队合作的重要性。

结对闪光点和建议:

  • 沈纪康:我认为我们的合作非常成功,但我们可以进一步改进时间管理,以确保更好地满足项目截止日期。此外,我们可以更频繁地检查并确认项目细节,以减少误解。
  • 石云欣:同意,我们可以在时间管理方面做得更好。此外,我建议我们在项目的早期阶段进行更明确的分工,以便更好地理解彼此的工作内容。

总结:
这个结对项目对我们来说是一次宝贵的经验,我们在项目中不仅学到了新知识,还提高了团队合作和问题解决的能力。我们将这些经验应用到未来的项目中,继续共同努力,共同成长。

标签:std,结对,压入,opr,四则运算,C++,num,操作符,stack
From: https://www.cnblogs.com/toasty/p/17735514.html

相关文章

  • 结对项目:python开发四则运算的程序
    项目链接软件工程软件工程链接作业要求作业要求的链接作业目标两人用python实现一个自动生成小学四则运算题目的命令行程序github项目链接github项目链接团队成员姓名学号李金强3121004868赵继业31210048901.PSP表格PSP表格通常用......
  • 结对项目:自动生成小学四则运算题目
    用Python实现一个自动生成小学四则运算题目的命令行程序 软件工程计科21级12班(广东工业大学-计算机学院)作业要求结对项目作业目标熟悉结对编程 成员姓名班级学号黄翼山计算机科学与技术2021级2班3119004783扎恩哈尔·吾兰计算机科学......
  • 结对项目:用Python实现自动生成小学四则运算题目的程序
    Python实现四则运算程序软件工程计科21级1.2班作业要求https://edu.cnblogs.com/campus/gdgy/CSGrade21-12/homework/13016作业目标完成结对项目:四则运算;熟悉团队协作的方法和模式github链接:https://github.com/howdnb/howdnb项目成员信息姓名学号......
  • 结对项目:实现一个自动生成小学四则运算题目的命令行程序
    1作业摘要与结对伙伴介绍1.1作业摘要这个作业属于哪个课程所属课程链接这个作业要求在哪里作业要求链接这个作业的目标<熟悉软件工程流程,把握PSP流程框架,精进测试代码和性能改进的能力>Github链接1.2结对伙伴信息姓名学号彭学智3121004878......
  • 结对项目:Java实现自动生成小学四则运算题目
    结队项目软件工程所在班级队伍成员谢昊天(3121004672)林育鑫(3121004660)作业要求[要求](([个人项目-作业-计科21级12班-班级博客-博客园(cnblogs.com)](结对项目-作业-计科21级12班-班级博客-博客园(cnblogs.com))))作业目标实现一个自动生成......
  • 结对项目
    一,成员信息表作业链接https://edu.cnblogs.com/campus/gdgy/CSGrade21-34/homework/13025拜尔克吐拉·吾买尔江3121005247阿布都瓦力·努尔买合买提3121005072Github链接https://github.com/bayer12/3121005247-bayer二,PSP表格PSP2.1PersonalSoftware......
  • 结对项目——贾基东&迪力木热提·开依散尔
    这个作业属于哪个课程计科21级12班这个作业要求在哪里结对项目这个作业的目标实现一个自动生成小学四则运算题目的命令行程序团队成员信息姓名学号贾基东3121004864迪力木热提·开依散尔3121004859gitee:https://gitee.com/jiajidong/3121004......
  • 结对项目
    作业概述这个作业属于哪个课程软件工程这个作业要求在哪里个人项目作业这个作业的目标完成小学四则运算算法”的设计并进行测试姓名学号陈梓鹏3121005208项目链接项目链接PSP表格PSP2.1PersonalSoftwareProcessStages预估耗时(分钟)实际耗时(分......
  • 实现自动生成小学四则运算题目
    这个作业属于哪个课程https://edu.cnblogs.com/campus/gdgy/CSGrade21-12这个作业要求在哪里https://edu.cnblogs.com/campus/gdgy/CSGrade21-12/homework/13016这个作业的目标结对项目GitHub链接1.PSP表格PSP2.1PersionalSoftwareProcessStages预估......
  • 结对项目
    课程地址https://edu.cnblogs.com/campus/gdgy/CSGrade21-12作业要求https://edu.cnblogs.com/campus/gdgy/CSGrade21-12/homework/13016作业目标进行结队项目尝试、实现小学四则运算的自动生成团队成员姓名学号高国豪3121004734黄家宝312100473......