注:本次结对编程是我与学号为2352231的同学共同完成。
一、算法设计思路
首先是随机数和随机运算符号的生成:随机数的生成是generateNumber() 函数通过 rand() % 100+1生成1到100之间的随机整数。rand()是C++ 标准库中的随机数生成函数rand()%100会得到0到 99之间的随机数,再加 1就得到了1到100之间的随机数。随机运算符生成也是根据生成随机数后generateOperator() 函数定义了一个包含 +、-、*、/ 四个运算符的字符数组 ops,然后通过 rand() % 4 随机选择一个运算符。
然后是表达式合法性检查,通过isValidExpression() 函数检查其合法性,该函数用于检查生成的表达式是否合法。合法的表达式需要满足两个条件:一是计算结果在0到1000之间;二是如果表达式中包含除法运算,除数不能为 0 且除法结果必须是整数。函数根据运算符的优先级,分三种情况计算表达式的结果:当前一个运算符是 * 或 /,后一个运算符是 + 或 - 时,先计算前两个数的结果,再与第三个数进行运算。当前一个运算符是 + 或 -,后一个运算符是 * 或 / 时,先计算后两个数的结果,再与第一个数进行运算。当两个运算符优先级相同时,从左到右依次计算。计算结果后,检查结果是否在 0 到 1000 之间,是否为 NaN 或无穷大,以及除法运算是否为整数。
合法表达式生成是通过generateValidExpression() 函数,该函数通过一个 do-while 循环不断生成随机的数字和运算符,直到生成的表达式通过 isValidExpression() 函数的合法性检查为止。
表达式计算的函数calculateExpression() 函数,该函数根据运算符的优先级计算表达式的结果,其计算逻辑与 isValidExpression() 函数中的计算逻辑基本相同,只是返回的是整数结果。
最后是退出命令检查isExitCommand() 函数:该函数用于检查用户输入是否为退出命令(quit、exit 或 q)。它会将用户输入的字符串转换为小写,然后进行比较。以及主程序逻辑初始化:在 main() 函数中,首先使用 srand(time(0)) 初始化随机数种子,确保每次运行程序时生成的随机数不同。定义总题数 totalQuestions 为 300,并初始化已答题数 answered 和答对题数 correct 为 0。循环答题:使用 while 循环,只要已答题数小于总题数,就继续生成新的表达式。调用 generateValidExpression() 函数生成合法的表达式,并输出给用户。获取用户输入,检查是否为退出命令。如果是,询问用户是否确认退出;如果不是,尝试将用户输入转换为整数。调用 calculateExpression() 函数计算表达式的正确答案,并与用户答案进行比较,给出相应的提示信息。更新已答题数和答对题数,并输出答题进度和正确率。结束练习:当已答题数达到总题数或用户确认退出时,输出最终成绩和完成情况。
二、确保运算的正确性检查
1.表达式合法性检查
在生成表达式时,代码会对表达式进行合法性检查,以避免出现不合法的运算,如除数为零、结果超出范围等情况,这一功能由 isValidExpression 函数实现。除数为零检查:在进行除法运算前,会检查除数是否为零。若除数为零,函数会直接返回 false,表示该表达式不合法。结果范围检查:计算表达式的结果后,会检查结果是否在 0 到 1000 之间。若结果不在此范围内,或者结果为 NaN(非数字)、无穷大,函数会返回 false。例如if (result < 0 || result > 1000 || isnan(result) || isinf(result)) { return false; }
整除检查:对于除法运算,会检查是否能整除。若不能整除,函数返回 false。例如:if (op1 == '/' && num1 % num2 != 0) return false;
2.运算优先级处理
代码会根据运算符的优先级正确计算表达式的结果,避免因运算顺序错误导致结果出错。在 isValidExpression 和 calculateExpression 函数中,对运算符优先级进行了处理。
先乘除后加减:当一个运算符为 * 或 /,另一个为 + 或 - 时,会先计算乘除运算,再计算加减运算。例如:if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) { // 先计算前两个数 if (op1 == '*') { result = num1 * num2; } else { if (num2 == 0) return false; // 除数为0 result = static_cast<double>(num1) / num2; } // 再与第三个数计算 if (op2 == '+') { result += num3; } else { result -= num3; } }
当两个运算符优先级相同时,会从左到右依次计算。
3.结果验证
在用户输入答案后,代码会将用户的答案与正确答案进行比较,以验证用户的计算是否正确。
会调用 calculateExpression 函数计算表达式的正确答案。
将用户输入的答案与正确答案进行比较,若相同则提示用户回答正确,若不同则提示回答错误并给出正确答案。示例代码如下:int correctAnswer = calculateExpression(num1, num2, num3, op1, op2); if (userAnswer == correctAnswer) { cout << "✓ 正确! "; correct++; } else { cout << "✗ 错误! 正确答案是: " << correctAnswer << ". "; }
4.输入验证
在获取用户输入时,代码会对输入进行验证,确保输入为有效的数字。使用 istringstream 尝试将用户输入转换为整数,若转换失败则提示用户输入数字或退出命令。示例代码如下:istringstream iss(userInput); if (!(iss >> userAnswer)) { cout << "请输入数字或退出命令!" << endl; continue; }
三、全部代码以及演示
点击查看代码
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <stack>
#include <cmath>
#include <sstream> // 对于istringstream
#include <cctype> // 对于tolower
using namespace std;
// 生成随机数 (1-100)
int generateNumber() {
return rand() % 100 + 1;
}
// 生成随机运算符 (+, -, *, /)
char generateOperator() {
char ops[] = { '+', '-', '*', '/' };
return ops[rand() % 4];
}
// 检查表达式是否合法(结果在0-1000之间且除法能整除)
bool isValidExpression(int num1, int num2, int num3, char op1, char op2) {
// 计算表达式结果
double result;
// 考虑运算符优先级
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
// 先计算前两个数
if (op1 == '*') {
result = num1 * num2;
}
else {
if (num2 == 0) return false; // 除数为0
result = static_cast<double>(num1) / num2;
}
// 再与第三个数计算
if (op2 == '+') {
result += num3;
}
else {
result -= num3;
}
}
else if ((op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-')) {
// 先计算后两个数
if (op2 == '*') {
result = num2 * num3;
}
else {
if (num3 == 0) return false; // 除数为0
result = static_cast<double>(num2) / num3;
}
// 再与第一个数计算
if (op1 == '+') {
result = num1 + result;
}
else {
result = num1 - result;
}
}
else {
// 从左到右计算
if (op1 == '+') {
result = num1 + num2;
}
else if (op1 == '-') {
result = num1 - num2;
}
else if (op1 == '*') {
result = num1 * num2;
}
else {
if (num2 == 0) return false; // 除数为0
result = static_cast<double>(num1) / num2;
}
if (op2 == '+') {
result += num3;
}
else if (op2 == '-') {
result -= num3;
}
else if (op2 == '*') {
result *= num3;
}
else {
if (num3 == 0) return false; // 除数为0
result /= num3;
}
}
// 检查结果是否在0-1000之间且为整数(如果是除法)
if (result < 0 || result > 1000 || isnan(result) || isinf(result)) {
return false;
}
// 检查除法是否为整数
if (op1 == '/' && num1 % num2 != 0) return false;
if (op2 == '/' && (op1 == '+' || op1 == '-') && num2 % num3 != 0) return false;
if (op2 == '/' && (op1 == '*' || op1 == '/') && (num1 * num2) % num3 != 0) return false;
return true;
}
// 生成合法表达式
void generateValidExpression(int& num1, int& num2, int& num3, char& op1, char& op2) {
do {
num1 = generateNumber();
num2 = generateNumber();
num3 = generateNumber();
op1 = generateOperator();
op2 = generateOperator();
} while (!isValidExpression(num1, num2, num3, op1, op2));
}
// 计算表达式结果
int calculateExpression(int num1, int num2, int num3, char op1, char op2) {
// 考虑运算符优先级
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
// 先计算前两个数
int firstResult;
if (op1 == '*') {
firstResult = num1 * num2;
}
else {
firstResult = num1 / num2;
}
// 再与第三个数计算
if (op2 == '+') {
return firstResult + num3;
}
else {
return firstResult - num3;
}
}
else if ((op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-')) {
// 先计算后两个数
int secondResult;
if (op2 == '*') {
secondResult = num2 * num3;
}
else {
secondResult = num2 / num3;
}
// 再与第一个数计算
if (op1 == '+') {
return num1 + secondResult;
}
else {
return num1 - secondResult;
}
}
else {
// 从左到右计算
int firstResult;
if (op1 == '+') {
firstResult = num1 + num2;
}
else if (op1 == '-') {
firstResult = num1 - num2;
}
else if (op1 == '*') {
firstResult = num1 * num2;
}
else {
firstResult = num1 / num2;
}
if (op2 == '+') {
return firstResult + num3;
}
else if (op2 == '-') {
return firstResult - num3;
}
else if (op2 == '*') {
return firstResult * num3;
}
else {
return firstResult / num3;
}
}
}
bool isExitCommand(const string& input) {
string lowerInput;
for (char c : input) {
lowerInput += tolower(c);
}
return lowerInput == "quit" || lowerInput == "exit" || lowerInput == "q";
}
int main() {
srand(time(0));
const int totalQuestions = 300;
int answered = 0;
int correct = 0;
cout << "四则运算练习题 (" << totalQuestions << "道题)" << endl;
cout << "每道题包含三个100以内的数字和两个运算符,请计算结果。" << endl;
cout << "输入'quit'或'exit'可以提前结束练习。" << endl;
cout << "----------------------------------------" << endl;
while (answered < totalQuestions) {
int num1, num2, num3;
char op1, op2;
generateValidExpression(num1, num2, num3, op1, op2);
cout << "第 " << answered + 1 << " 题: "
<< num1 << " " << op1 << " "
<< num2 << " " << op2 << " "
<< num3 << " = ?" << endl;
string userInput;
cout << "你的答案(或输入quit退出): ";
cin >> userInput;
// 检查是否要退出
if (isExitCommand(userInput)) {
cout << "你要提前结束练习吗?(y/n): ";
char confirm;
cin >> confirm;
if (tolower(confirm) == 'y') {
break;
}
else {
continue;
}
}
// 尝试将输入转换为数字
int userAnswer;
istringstream iss(userInput);
if (!(iss >> userAnswer)) {
cout << "请输入数字或退出命令!" << endl;
continue;
}
int correctAnswer = calculateExpression(num1, num2, num3, op1, op2);
if (userAnswer == correctAnswer) {
cout << "✓ 正确! ";
correct++;
}
else {
cout << "✗ 错误! 正确答案是: " << correctAnswer << ". ";
}
answered++;
cout << "进度: " << answered << "/" << totalQuestions
<< " (正确率: " << (correct * 100 / answered) << "%)" << endl;
cout << "----------------------------------------" << endl;
}
cout << "\n练习结束! 你的最终成绩: " << correct << "/" << answered
<< " (正确率: " << (answered > 0 ? correct * 100 / answered : 0) << "%)" << endl;
if (answered < totalQuestions) {
cout << "你提前结束了练习,完成了 " << answered << " 道题。" << endl;
}
else {
cout << "恭喜你完成了所有 " << totalQuestions << " 道题!" << endl;
}
return 0;
}


四、结对编程感受
经过这次结对编程作业,让我有了以下几点感受:
1.结对编程可以快速成长与查漏补缺,以往独自编程时,容易陷入惯性思维,遇到问题常因认知局限而停滞。结对编程中,伙伴能从不同视角切入问题。比如在优化算法复杂度时,我执着于局部调整,伙伴却提出重构数据结构的新思路,这种思维碰撞让我突破瓶颈,学习到新的技术方法。同时,互相 讨论代码的过程,也让我发现自己编码习惯中的潜在风险,这些细节问题的修正极大提升了我的编码质量。
2.起初,在他人注视下编码会倍感压力,担心因操作不熟练或思路卡顿被否定。但随着合作深入,压力逐渐转化为动力。当我们共同攻克复杂一点的逻辑,或是用简洁的代码实现需求时,那种成就感远超个人完成项目的体验。而且,在伙伴的鼓励下,我更敢于尝试新方法,即使失败也能迅速调整心态。