122
社区成员
发帖
与我相关
我的任务
分享| 这个作业属于哪个课程 | 2302软件工程 |
|---|---|
| 这个作业要求在哪里 | 软件工程第二次作业--文件读取 |
| 这个作业的目标 | 完成对数据项目的抓取 |
| 其他参考文献 | 《构建之法》、工程师的能力评估和发展、单元测试和回归测试、Microsoft Visual Studio 文档 |
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 预估耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 40 | 30 |
| • Estimate | • 估计这个任务需要多少时间 | 40 | 30 |
| Development | 开发 | 1800 | 2000 |
| • Analysis | • 需求分析 (包括学习新技术) | 150 | 160 |
| • Design Spec | • 生成设计文档 | 30 | 40 |
| • Design Review | • 设计复审 | 20 | 40 |
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 10 | 20 |
| • Design | • 具体设计 | 30 | 25 |
| • Coding | • 具体编码 | 1400 | 1550 |
| • Code Review | • 代码复审 | 40 | 45 |
| • Test | • 测试(自我测试,修改代码,提交修改 | 120 | 130 |
| Reporting | 报告 | 70 | 70 |
| • Test Repor | • 测试报告 | 60 | 60 |
| • Size Measurement | • 计算工作量 | 20 | 20 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 20 | 20 |
| 合计 | 1910 | 2100 |
首先要明白这个项目的目的是什么,其次就是需要实现的功能有哪些。
当然,在此之前,先要规定一下代码风格,工欲善其事必先利其器。
前人的经验是很重要的,要求里也提供了往届的优秀作业,于是先去看了一遍,了解了大概过程。在脑海中有一个大致的印象,接下来就是对着作业的功能要求一步步地去完成,这样先总后分,有条不紊。
以及在完成功能之前要先对json数据进行相应的分析。
资料大部分当然是在CSDN上寻找了:)
理解需求: 首先,仔细阅读题目,理解DWASearch的功能要求,包括输出选手信息、比赛结果等。
分析输入和输出: 将不同指令的输入与输出进行分析,了解各个功能的要求和输出格式,注意处理空格和格式的要求。
模块设计: 将基本功能拆分,设计类或函数来处理这些功能。
处理指令: 在程序中添加逻辑,根据输入的指令执行相应的功能模块。
数据处理: 考虑如何处理爬取的数据,可能需要设计数据结构来存储选手信息和比赛结果。
异常处理: 实现对错误指令的处理,如无法识别的指令,输出Error。
性能分析: 进行性能分析,确保程序在处理大量数据时仍能保持高效。
接口封装: 根据需求,设计模块,将基本功能封装,以便在不同环境中使用。
单元测试: 设计多个测试用例,确保程序能够正确处理各种情况,包括正常输入和异常情况。
文档编写: 编写清晰的注释和文档,使其他人能够理解和使用代码。
定期提交: 按照项目进度,定期提交代码,确保整个项目的稳步推进。






首先,功能是关于cmd命令的,要实现这个功能其实主要就是main函数传入的参数设置。我这里遇到了一些问题,最后查csdn博客得知,argv[0]原来固定是程序名...
接下来考虑第一个功能,players的打印,(Json的爬取在往届作业里已经很详尽了,于是偷懒用现成·),有了Json后呢,如何解析?在网络上找了很多资料,发现了c++上比较好用的Json解析库--nolohmann
在写识别result和detail指令的时候一直出现out_of_range的报错,换了好几种写法依旧没有办法解决,最后排查是没有考虑特殊情况的原因,特别是当字符串为空,或者字符串只有一个单词时候的情况,花了很多时间去调试才找到这个错误原因...
开发完功能后就要进行一系列的测试,修复了一堆bug
到后面还发现players的排序是要stable_sort的
接下来请欣赏我的程序设计:)
Score: 用于存储分数信息。Player: 用于存储选手信息。
cmpPlayers: 用于按照国家和姓氏排序选手。removeLastWord, removeFirstWord, isLastWordDetail, isFirstWordResult, toLowerCase: 提供一些字符串处理和判断功能。printPlayers, printResult, printResultDetail: 负责从 JSON 文件读取数据并输出相应信息。getID: 根据事件名称从 event.json 文件中获取对应的事件ID。readCommand: 读取指令并根据指令调用相应的打印函数。
主要的关键代码位于打印函数和事件ID获取函数。以下是关键函数的思路和代码示例:
printPlayers: 从 JSON 文件读取选手信息,排序后输出。关键之处在于使用了结构体 Player 存储选手信息,并利用 cmpPlayers 函数进行stable_sort排序。
void printPlayers(std::ofstream& outputFile) {
// 读取选手信息并存储在 players 向量中
// 排序选手信息
// 输出选手信息
}
printResult: 从 JSON 文件读取比赛结果并输出选手详情、排名和分数。利用了结构体 Score 存储分数信息。
void printResult(std::string ID, std::ofstream& outputFile) {
// 读取比赛结果信息
// 输出选手信息、排名和分数
}
printResultDetail: 从 JSON 文件读取详细比赛结果并输出选手详情、排名和分数。此函数较为复杂,因为需要处理不同比赛轮次和选手的数据。算法的精髓:因为发现Json的比赛顺序从前到后先是决赛再是半决赛最后是初赛,所以从后往前搜到的第一个就是这整个比赛的第一场比赛。
void printResultDetail(std::string ID, std::ofstream& outputFile) {
// 读取详细比赛结果信息
// 处理不同比赛轮次的数据,输出选手详情、排名和分数
}
getID: 根据事件名称从 event.json 文件中获取对应的事件ID。
void getID(std::string name, std::string& ID) {
// 从 event.json 中读取数据,找到匹配的事件ID
}
全局变量:
players、IDToResultMap、IDToResultDetailMap 改为全局变量。vector<Player> players; // 选手信息缓存
unordered_map的使用:
unordered_map 存储选手名字到索引和ID到选手数组的映射,在结果的处理中,避免了对数组的多次遍历,减少了搜索时间。unordered_map<string, int> nameToPlayer; // 选手名字到索引的映射
unordered_map<string, vector<Player>> IDToResultMap; // ID到结果的选手数组的映射
unordered_map<string, vector<Player>> IDToResultDetailMap; // ID到详细结果的选手数组的映射
缓存更新策略:
if (IDToResultMap.find(ID) == IDToResultMap.end()) {
// 如果缓存中不存在比赛结果,则进行文件读取和数据处理,并更新缓存
// ...
} else {
// 直接使用缓存中的比赛结果数据
players = IDToResultMap[ID];
}
<fstream>头文件中的ifstream(用于文件输入),ofstream(用于文件输出。这些类都支持缓冲操作,意味着它们会将数据暂存于内存中的一个缓冲区,然后批量处理,这样可以减少对磁盘的直接读写次数,从而提高效率。对多次输入同一指令的input
(ps:总共100行指令,且改进前后都使用缓存输入输出)
改进前:
0.7764s
改进后:
0.2822s
结论:对上述input,速度快了0.5s左右,快了63.7%左右
测试用例包含以下情况:
部分样例展示:
vs2019覆盖率的查看只有专业版能用(哭腔一个月250美元的专业版怎么不去抢钱
但是,
没有关系!
我在gittub上面找到了一个免费的插件:FindCodeCoverage
装上以后测覆盖率:
什么!!怎么50%都不到?
展开All发现,原来只是引用的库里有一堆代码没用到而已
我编写的代码的覆盖率是94.6%
为了优化覆盖率,还有以下建议:
命令行参数检查:
argc 和 argv 确保程序接收到正确数量的命令行参数(这里是 3 个参数)。if (argc != 3) {
std::cout << "Error on argv.\n";
return 1;
}
文件打开异常处理:
if (!inputFile) {
std::cout << "Failed to open input file.\n";
return 1;
}
if (!outputFile) {
std::cout << "Failed to open output file.\n";
return 1;
}
首先是对git的运用更加熟悉了,其次是对Json解析更加熟悉了,之前有个移动应用开发的课也有解析Json,但是这次更加深刻的了解了一遍。更加重要的是为项目开发算是累积了一些经验,因为走完了完整的开发流程,算是一次非常充分的热身吧!相信这些弥足珍贵的经验会为我的未来计算机之路做出不小的贡献:)