软件工程第二次作业

前言

一位乘客突然失去了梦想


  • 作业描述
  • 仓库地址
    注:由于采用命令行之后在VS2015上不能正常运行、故以下相关测试main函数里面未添加命令行。

解题思路

  • 解法1.0:因为数独局面行列的数字都完全不相同,可类比N皇后问题,创建一个81x9的二维数组、每个棋盘(9x9)产生一个N皇后(皇后分别用1-9的数字代替)的解法,最后再结合81行产生一个局面;
    解法分析:最后求解数独解局面实现较为复杂,每个棋盘合并有点类似临摹的思想,在当前棋盘的空白局面临摹下一个棋盘的局面且不影响当前已临摹的局面;
  • 解法2.0:产生一个空白的9x9的二维矩阵、从0-80一位一位去枚举判断,直至产生一个可解局面,本次作业采用此解法

实现过程

共2个类,其实可以一个,SudokuProduce类主要是用来产生数独局面,Check类主要用来判断输入是否合法(这个实际应用有点鸡肋,可去除,将判断直接放在main函数里面)
SudokuProduce共4个成员函数分别为JudgeProduceDFSRandperm,分别作为判断、产生局面、递归枚举、产生随机数;
主要依赖关系:Produce通过调用DFS来产生数独局面,Randperm为DFS提供可枚举的随机数,枚举可行方案由Judge判定
写得有点乱......

代码说明

void SudokuProduce::DFS(int num)
{
    int row = num / 9;
    int col = num % 9;
    if (num>80)
    {
        flag = true;
        return;
    }
    if (soduku[row][col] != 0)
    {
        DFS(num + 1);
    }
    else
    {
        /*因为九个数随机排列最多只有9!=362880种,故在此设置中间过程
        以避免数据量超过这个数时产生相同随机序列导致产生相同的数独局面*/
        if (num % 25 == 0)
        {
            std::random_shuffle(temp.begin(), temp.end());
        }
        for (int i = 0; i<9; i++)
        {
            if (Judge(num, temp[i]) == true)
            {
                soduku[row][col] = temp[i];
                DFS(num + 1);
                if (flag == true) 
                { 
                    return;
                }
                else
                {
                    soduku[row][col] = 0;
                }
            }
        }
    }
}

这里的temp是一个随机1-9的序列,如果直接从1-9枚举会遇到当你要多个数独局面的时候产生近似或者完全相同的局面,故这里采用C++库函数random_suffle产生1-9随机序列且不重复(PS:采用rand会产生重复随机数,故需进行多次rand才能获取一个不重复的随机序列、而random_suffle只需一次即可)
具体实现如下:

template<class RandomAccessIterator>
void random_shuffle(
    RandomAccessIterator _First,
    RandomAccessIterator _Last
);
void SudokuProduce::Randperm()
{
    for (int i = 0; i < 9; ++i)
    {
        temp.push_back(i + 1);
    }
}

通过调用std::random_shuffle(temp.begin(), temp.end());实现产生随机数

运行实例

这里加入了对第二个参数是否规范的判断及第三个参数有无的判断并输出相应提示信息

性能分析

初版本还包含了一个Print类,跑1000的数据性能分析下来发现这里占用CPU较多,如下

由上图可知Print类里函数耗时较多、主要花费在文件的不断打开与关闭中,故将输出改至SudokuProduce类中,并删去Print类,修改完性能如下

这里的外部代码主要是filebuff即文件缓冲,因为是一个个输出,所以会比较慢,考虑将数字转化为字符串输出提高效率,修改后跑10w数据性能如下

上图时间主要花费在深搜回溯上,故要再提升性能只能考虑修改算法思想······

单元测试(惨绝人寰)

写单元测试时,在网上百度了各种教程、摸爬滚打、写了出来又各种报错、各种LNK2011 1120等问题,解决完的时候感觉像是上天了一样····扯得有点远了
第一次写单元测试,就写了一个类的两个测试(不知道是不是两个类的话要分别建一个单元测试的项目还是什么,自己试了写在一起就各种报错了,分开写也报错,很无奈)。。。
所以只写了Check类的测试,具体如下

单元测试之代码覆盖率

概括:过程是艰辛的,结局是失败的;怎么说呢?花了一下午+一晚上的时间弄opencover,在成功搞上编译器之后,去试了一下,emmmm......结果一直显示不出来,也不知道是哪里配置错误了,还在研究中,这个就放空了(溜了溜了)·······
emmmm......好像是这个??????因为就写了两个测试函数而已,所以可能还需要再多写几个········

PSP(还不是很懂里面各个项的含义,所以蛮填一下,一些指标没填的像生成设计文档这个真的就没去写过。。。。)

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 20
· Estimate · 估计这个任务需要多少时间 60 120
Development 开发 240 600
· Analysis · 需求分析 (包括学习新技术) 60 140
· Design Spec · 生成设计文档 - -
· Design Review · 设计复审 (和同事审核设计文档) - -
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) - -
· Design · 具体设计 60 120
· Coding · 具体编码 150 400
· Code Review · 代码复审 120 120
· Test · 测试(自我测试,修改代码,提交修改) 100 480
Reporting 报告 30 30
· Test Report · 测试报告 100 180
· Size Measurement · 计算工作量 10 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 - -
合计 950 2220
posted @ 2017-09-10 20:25  Distances  阅读(237)  评论(3编辑  收藏  举报