软工第三次作业——结对项目

软工第三次作业

这个作业属于哪个课程 班级链接
这个作业要求在哪里 作业要求
这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序
姓名 学号 github地址
黎火坤 3123004310 https://github.com/Keygener53/3123004310-project2
高泽彤 3123004304 https://github.com/Tomgao4116/3123004304

1、PSP表格

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

2、效能分析

对比之前版本的改进思路:通过栈结构减少临时变量,并支持文件的批量输入输出,节省了内存空间与运行时间,算法的最坏时间复杂度从O(n^3) 提升到 O(n^2)。

该项目中性能消耗最大的是calculate函数,最坏情况的时间复杂度是O(n^2),平均时间复杂度是O(n log n)

3、设计实现过程

微信图片_20251022203222_268_13

1、代码有一个ExpressionGenerator 类,它的功能是生成数学表达式

2、函数
主函数main(int argc, char argv[]) 作为程序入口点*

主要功能函数

  1. build(string x, string y)
    · 构建表达式节点,处理数字、运算符和括号
  2. write()
    · 解析输入字符串,构建表达式序列
  3. calculate()
    · 核心计算函数,处理表达式求值
  4. calNumber(node pre, node v)
    · 执行具体的数学运算(加减乘除)
  5. reserve()
    · 输出计算结果

辅助函数

  1. add(ll a, ll b, ll c, ll d) - 分数加法
  2. sub(ll a, ll b, ll c, ll d) - 分数减法
  3. mul(ll a, ll b, ll c, ll d) - 分数乘法
  4. mins(ll a, ll b, ll c, ll d) - 分数除法
  5. printHelp() - 打印使用帮助
  6. judging() - 评判结果统计
  7. clearSpace() - 清理临时数据
  8. solve() - 解决表达式计算问题
  9. readin(int argc, char* argv[]) - 处理命令行参数

4、代码说明

以下列举了几个主要函数代码

1、build处理表达式函数

点击查看代码
void build(string x,string y){
    if(x=="("){  // 左括号节点
        b.push_back({0,0,x,y});
    }else if(x==")"){  // 右括号节点
        if(y=="+"||y=="*"||y=="-"||y=="%"){
            b.push_back({0,0,x,y});
        }else{
            b.push_back({0,0,x,"NAN"});
        }
    }      //‘%’代表除法
    else{ 
        ll num=0;
        vector<ll> tmp;
        x+="/";  // 分隔符‘/’代表分数
        
        // 解析数字(可能是整数或分数)
        for(int i=0;i<x.size();i++){
            if(x[i]>='0'&&x[i]<='9'){
                num=num*10+x[i]-'0';
            }else{
                tmp.push_back(num);
                num=0;
            }
        }
        
        if(tmp.size()==1){  // 整数
            if(!(y=="+"||y=="*"||y=="-"||y=="%")){
                b.push_back({tmp[0],1ll,"NUM","NAN"});
            }else{
                b.push_back({tmp[0],1ll,"NUM",y});
            }
        }else{  // 分数
            if(!(y=="+"||y=="*"||y=="-"||y=="%")){
                b.push_back({tmp[0],tmp[1],"NUM","NAN"});
            }else{
                b.push_back({tmp[0],tmp[1],"NUM",y});
            }
        }
    }
}

2、calculate计算函数

点击查看代码
 //核心计算函数,使用栈计算表达式值
void calculate(){
    for(auto v:b){  // 遍历所有表达式节点
        if(!st.size()){  // 栈空,直接压入
            st.push(v);
        }else{
            // 尝试计算栈顶的两个数字节点
            if(st.size()>1){
                node x1=st.top();
                st.pop();
                node x2=st.top();
                if(x1.st=="NUM"&&x2.st=="NUM"){  // 都是数字,可以计算
                    node ans=calNumber(x2,x1);
                    st.push(ans);
                }else{            // 恢复栈状态
                    st.push(x1);
                }
            }
            
            node pre=st.top();  // 获取栈顶元素
            
            if(v.st=="("){  // 左括号,压入栈
                st.push(v); 
            }else if(v.st==")"){  // 右括号,弹出直到左括号
                node num=st.top();  // 数字
                st.pop();
                st.pop();  // 左括号
                st.push({num.u,num.d,"NUM",v.nxt});  // 数字带操作符
            }else{  // 数字节点,进行计算
                node ans=calNumber(pre,v);
                if(ans.u<0)tag2=1;  // 标记负数
                st.push(ans);
            }
        }
    }

3、readin处理命令行函数

点击查看代码
//处理从命令行读入数据 +生成数据: 
int readin(int argc,char* argv[]){
	int n = 0;
    int r = 0;
    bool hasR = false;
    // 解析命令行参数
    for (int i = 1; i < argc; i++) {
        std::string arg = argv[i];
        if (arg == "-n" && i + 1 < argc) {
            n = std::stoi(argv[++i]);
        } else if (arg == "-r" && i + 1 < argc) {
            r = std::stoi(argv[++i]);
            hasR = true;
        } else if (arg == "-h" || arg == "--help") {
            printHelp();
            return 0;
        }
    }
    // 检查必要参数
    if (!hasR) {
        std::cout << "Error: -r parameter is required!" << std::endl;
        printHelp();
        return 1;
    }
    
    if (n <= 0) {
        std::cout << "Error: -n parameter must be positive!" << std::endl;
        printHelp();
        return 1;
    }
    
    if (r <= 1) {
        std::cout << "Error: -r parameter must be greater than 1!" << std::endl;
        printHelp();
        return 1;
    }
    // 生成表达式
    ExpressionGenerator generator(r);
    std::vector<Expression*> expressions = generator.generateExpressions(n);
    ofstream outfile("F:/homework3/Exercises.txt");
    // 输出结果(新格式:没有等号)
    for (size_t i = 0; i < expressions.size(); ++i) {
        std::cout<<i+1<< " : " << expressions[i]->toString() << std::endl;
        outfile<< expressions[i]->toString()<<std::endl;
    }
    std::cout<<"数据已保存至:Exercises.txt文件中"<<'\n'; 	
    // 清理内存
    for (Expression* expr : expressions) {
        delete expr;
    }
    outfile.close();
}

5、测试运行

1、20个测试用例

屏幕截图 2025-10-22 222734

2、程序正确性解释

1.使用正确的数学表达式思路,正确处理运算符优先级

void calculate() {
// 通过栈结构处理运算符优先级:
// 1. 高优先级(*,%)立即计算
// 2. 低优先级(+,-)在适当时候计算
// 3. 括号改变计算顺序
}

2.进行了各种边界情况处理

除零保护

点击查看代码
pll mins(ll a,ll b,ll c,ll d) {
    // 由于ExpressionGenerator保证生成合法表达式,不会出现d=0的情况
    ll up = b*c;
    ll down = a*d;  // 如果d=0,这里会崩溃,但生成器保证不会发生
    ll g = __gcd(up,down);
    up/=g,down/=g;
    return {up,down};
}

负数检测

点击查看代码
node ans = calNumber(pre,v);
if(ans.u<0)tag2=1;  // 检测到负数,标记为不合法

零值处理

点击查看代码
if(answer.u==0) {  // 结果为0
    std::cout<<cnt<<" : "<<0<<'\n';
    // 正确输出0,而不是0/1等形式
}

3.有错误处理机制

参数验证

点击查看代码
if (r <= 1) {
    std::cout << "Error: -r parameter must be greater than 1!" << std::endl;
    printHelp();
    return 1;  // 正确退出并提示
}

表达式合法性检查

点击查看代码
if(tag2) {  // 有负数,表达式不合法
    std::cout<<cnt<<" : "<<"算式不合法!"<<'\n';
    return;  // 跳过当前题目的正常输出
}

6、项目小结

该结对项目是一个基于C++开发的四则运算表达式生成与计算系统,由两名成员合作完成。系统具备表达式自动生成、智能计算和结果验证等功能,支持分数运算和括号优先级处理。

1.合作分工:

一人负责算法核心开发和代码编写,另一人负责代码检查和博客撰写。

2.本次结对项目途中有不少挑战,主要包括以下几个:

· 挑战1:分数运算的精度问题
· 解决方案:采用分子分母分别存储,避免浮点数误差
· 挑战2:运算符优先级处理
· 解决方案:设计nxt字段标记下一个操作符,实现延迟计算
· 挑战3:负数结果检测
· 解决方案:在计算过程中实时监

3.未来的改进方向:

  1. 性能优化:支持更大规模的表达式计算
  2. 功能扩展:增加更多运算符和函数支持
  3. 用户体验:改进命令行界面,增加交互模式
  4. 测试完善:增加单元测试和性能测试

通过本次合作项目,我们不仅成功开发了一个功能完整的四则运算系统,更重要的是在实践中学习了团队协作、软件设计和算法实现的宝贵经验。项目的成功得益于明确的分工、良好的沟通和对技术细节的深入钻研。这个系统展示了如何将理论知识转化为实际可用的软件产品,为我们未来的软件开发工作奠定了坚实的基础。

posted @ 2025-10-22 22:56  Keygener53  阅读(0)  评论(0)    收藏  举报