第4周小组作业:WordCount优化

时间:2022-12-20 08:11:23

第4周小组作业:WordCount优化

一、基本任务:代码编写+单元测试

小组github 地址 

https://github.com/iwannastay/WcPro 源代码及可运行程序位于branch->stage3 下的 stage3 文件夹, 或在tag stage3中直接下载


 

PSP表格

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

接口设计

  • 接口描述

    我负责的模块是单词排序,即由外部传入各单词词频,模块将其排序并输出。

  • 设计思路

    由于是数目未知的数值元素,故可以将输入输出接口定义为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;
}

 


测试设计

  保证设计的测试用例应至少覆盖函数中所有的可执行语句,同时主要空数组、最差情况、词频排序、字母排序、两者混合等各种情况设计测试用例。

第4周小组作业:WordCount优化

 


单元测试

试用测试脚本进行单元测试,过程如下:

第4周小组作业:WordCount优化

单元测试效果较好,测试结果均正确,且排序性能较高。


 

小组贡献

  我们小组齐心协力,共克难关,积极讨论并指出其他组员的问题,最终得出我的小组贡献分为0.3。

 

二、扩展任务:静态测试

1.代码规范

  我选择了代码风格规范中:断行与空白的{}行、分行、命名、下划线、大小写;

      代码设计规范中:函数、gogo、错误处理、断言(在其他大型程序中常用,在本次作业中未使用)、析构函数、new和delete、类型继承。

  我的编程习惯与以上附录中所述规范大致相同,少许部分持不同意见。而在其他如代码审查等重要规范上有待提高。


 

2.同组分析

  我分析了组员17027的代码,缩进、断行风格整洁,命名简单明了,逻辑清晰易读,较好地遵守了设计规范。


3.静态代码检查工具

  使用Visual Studio 2015 内置检测工具,可在微软官方网站https://www.visualstudio.com/zh-hans/downloads/下载


 

4.扫描结果

第4周小组作业:WordCount优化

以上问题说明代码存在数据丢失以及内存泄漏等问题,应尽量少使用格式自动转换。


5.小组代码问题说明

  • 数据结构较为冗杂,降低了程序性能,应减少不必要的类的使用;
  • 异常处理不够全面,应该覆盖大部分的异常情况,以便于检查。

 

 

三、高级任务:性能测试和优化 

  设计,评审,优化

  选择10kb,20kb,50kb大小的txt文件进行测试,程序处理时长如下:

      输入输出:13ms,14ms,16ms

      单词统计:740ms,1500ms,3800ms

      词频排序:11ms,12ms,22ms

  单词统计时间与文件大小呈线性相关,其他两个模块占比较小,故程序性能主要受到文件大小影响。组内共同对代码结构和细节进行详细审查,整理得到优化思路如下:

    1.将统计部分中的大小写转换提取成单个模块,能大幅度减少转换函数的调用次数,随着文件越大效果越明显;

    2.增加单次提取字符数量,减少主框架循环次数;

    3.将字母排序单独提取成一个模块,即将排序算法中的比较函数替换为纯数值比较,减少内存开销,减少排序时间,最后再遍历数组重新调整同频单词顺序,此方法在数组较大时能够提高程序效率。


 

  附加题

   使用MFC开发环境,设计具有图形界面的文件选择工具。

第4周小组作业:WordCount优化

第4周小组作业:WordCount优化

 


  小结

  通过基本任务、扩展任务、到高级任务的完成以及中间遇到的许多困难,体现出了软件测试对于软件开发的重要性。在开发过程中,使用静态测试工具实时地检测自己的代码,可以改正自己不良的编程习惯,更能防患于未然,减少出现bug的可能;对自己的模块进行单元测试,可以保障自己代码的正确性,更是对其他开发成员和整个任务的负责,使软件开发能够一步一个脚印地稳定开展;对性能的分析与测试,能使软件的质量进一步提高,同事能总结开发经验,使自己设计的模块更加高效。