结对编程作业以及感受

注:本次结对编程是我与学号为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.起初,在他人注视下编码会倍感压力,担心因操作不熟练或思路卡顿被否定。但随着合作深入,压力逐渐转化为动力。当我们共同攻克复杂一点的逻辑,或是用简洁的代码实现需求时,那种成就感远超个人完成项目的体验。而且,在伙伴的鼓励下,我更敢于尝试新方法,即使失败也能迅速调整心态。