https://github.com/iwannastay/WcPro/tree/stage3/stage3 git
PSP2.1 | PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 60 |
Estimate | 估计任务须要多少时间 | 30 | 60 |
Development | 开发 | 180 | 240 |
Analysis | 需求分析 | 20 | 30 |
Design Spec | 生成设计文档 | 20 | 30 |
Design Review | 设计复审 | 20 | 30 |
Coding Standard | 代码规范 | 30 | 10 |
Design | 具体设计 | 30 | 50 |
Coding | 具体编码 | 30 | 40 |
Code Review | 代码复审 | 30 | 40 |
Test | 测试 | 50 | 10 |
Reporting | 报告 | 70 | 240 |
Test Report | 测试报告 | 30 | 100 |
Size Measurement | 计算工做量 | 20 | 60 |
Postmortem | 总结 | 20 | 80 |
合计 | 340 | 540 |
我负责的模块是单词排序,即由外部传入各单词词频,模块将其排序并输出。github
因为是数目未知的数值元素,故能够将输入输出接口定义为vector<int>数组;数组的排序能够选择多种算法如插入排序、合并排序、基数排序、桶排序、快速排序等,因为处理的文本可能极大,对算法性能要求较高,故此选择随机快排实现该接口;然而本程序包含额外的条件——1.单词词频同步输出,2.同频的单词按照字母顺序排列,故不能仅用单词的词频做为接口,而需将单词自己的索引输入,因为外部数据结构未知,故直接引用单词自己做为参数,即便用vector<pair<string,int>>做为模块外部接口。算法
因为外部存储结构使用map<pair<string,int>>,且map的实现机制是红黑树的平衡二叉树,不支持索引操做,为了便于排序,需进行map->vector的转换。编程
//词频排序 void WcFile::RankProcess() { int count = 0, size = Word_List.size(); map<string, int>::iterator iter = Word_List.begin(); while (iter != Word_List.end()) { Rank_List.push_back(*iter); iter++; } //随机快排 Random_Quick_Sort(Rank_List, 0, Rank_List.size() - 1); }
排序算法实现数组
//快速排序分划程序 int WcFile::Partition(vector<pair<string, int>> &A, int p, int q) { auto x = A[p]; int i = p; for (int j = p + 1; j <= q; j++) { if (ComparePriority(A[j],x)) { i = i + 1; Swap(A[i], A[j]); } } Swap(A[p], A[i]); return i; } //随机化快速排序分划程序 int WcFile::Random_Partition(vector<pair<string, int>> &A, int p, int q) { int i = rand() % (q - p) + p; Swap(A[i], A[p]); return Partition(A, p, q); } //随机化快速排序 void WcFile::Random_Quick_Sort(vector<pair<string, int>> &A, int p, int q) { if (p < q) { int i = Random_Partition(A, p, q); Random_Quick_Sort(A, p, i - 1); Random_Quick_Sort(A, i + 1, q); } } //交换元素 void WcFile::Swap(pair<string, int> &m, pair<string, int> &n) { pair<string, int> tmp; tmp = m; m = n; n = tmp; } //首字母排序 bool WcFile::ComparePriority(pair<string, int> &m, pair<string, int> &n) { if (m.second != n.second) return m.second > n.second ? true : false; else return m.first < n.first ? true : false; }
保证设计的测试用例应至少覆盖函数中全部的可执行语句,同时主要空数组、最差状况、词频排序、字母排序、二者混合等各类状况设计测试用例。数据结构
试用测试脚本进行单元测试,过程以下:框架
单元测试效果较好,测试结果均正确,且排序性能较高。dom
咱们小组齐心合力,共克难关,积极讨论并指出其余组员的问题,最终得出个人小组贡献分为0.3。函数
我选择了代码风格规范中:断行与空白的{}行、分行、命名、下划线、大小写;工具
代码设计规范中:函数、gogo、错误处理、断言(在其余大型程序中经常使用,在本次做业中未使用)、析构函数、new和delete、类型继承。
个人编程习惯与以上附录中所述规范大体相同,少量部分持不一样意见。而在其余如代码审查等重要规范上有待提升。
我分析了组员17027的代码,缩进、断行风格整洁,命名简单明了,逻辑清晰易读,较好地遵照了设计规范。
//导入文件 bool WcFile::LoadFile(const char *_filename) { File_Name = _filename; File_Stream.open(File_Name); if (!File_Stream) { cout << "Fail to open the source file:" << File_Name << endl; system("exit"); } return true; } //保存结果 void WcFile::SaveResult() { File_Stream.close(); File_Stream.open(ResultFile_Name); if (!File_Stream) { cout << "Fail to open the result file." << endl; system("exit"); } for (int i = 0; i < 100 && i < Rank_List.size(); i++) File_Stream << Rank_List[i].first << "\t" << Rank_List[i].second << endl; File_Stream.close(); }
使用Visual Studio 2015 内置检测工具,可在微软官方网站https://www.visualstudio.com/zh-hans/downloads/下载
以上问题说明代码存在数据丢失以及内存泄漏等问题,应尽可能少使用格式自动转换。
选择10kb,20kb,50kb大小的txt文件进行测试,程序处理时长以下:
输入输出:13ms,14ms,16ms
单词统计:740ms,1500ms,3800ms
词频排序:11ms,12ms,22ms
单词统计时间与文件大小呈线性相关,其余两个模块占比较小,故程序性能主要受到文件大小影响。组内共同对代码结构和细节进行详细审查,整理获得优化思路以下:
1.将统计部分中的大小写转换提取成单个模块,能大幅度减小转换函数的调用次数,随着文件越大效果越明显;
2.增长单次提取字符数量,减小主框架循环次数;
3.将字母排序单独提取成一个模块,即将排序算法中的比较函数替换为纯数值比较,减小内存开销,减小排序时间,最后再遍历数组从新调整同频单词顺序,此方法在数组较大时可以提升程序效率。
使用MFC开发环境,设计具备图形界面的文件选择工具。
经过基本任务、扩展任务、到高级任务的完成以及中间遇到的许多困难,体现出了软件测试对于软件开发的重要性。在开发过程当中,使用静态测试工具实时地检测本身的代码,能够改正本身不良的编程习惯,更能防患于未然,减小出现bug的可能;对本身的模块进行单元测试,能够保障本身代码的正确性,更是对其余开发成员和整个任务的负责,使软件开发可以一步一个脚印地稳定开展;对性能的分析与测试,能使软件的质量进一步提升,同事能总结开发经验,使本身设计的模块更加高效。