软件工程实践2019第三次作业

- Github项目地址

https://github.com/33lc/031702211


- PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划
Estimate估计这个任务需要多少时间1515
Development开发
Analysis需求分析 (包括学习新技术)120180
Design Spec生成设计文档6090
Design Review设计复审3040
Coding Standard代码规范 (为目前的开发制定合适的规范)6045
Design具体设计6060
Coding具体编码240180
Code Review代码复审6060
Test测试(自我测试,修改代码,提交修改)120150
Reporting报告
Test Repor测试报告150180
Size Measurement计算工作量4030
Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划60100
合计10151130

- 计算模块接口的设计与实现过程

void clear(int m);
void input(int m);
void output(int m);
int check(int step,int i,int j,int x);
int build(int step,int i,int j);
int search0(int step);

1. clear函数
由于存在多个盘面需要求解,故在每次解之前需将程序中原数组进行清零,clear函数便用于执行清零操作。

void clear(int step)            //step为阶数
{
    int i, j;
    for (i = 0; i < step; i++)
        for (j = 0; j < step; j++)
            sd[i][j] = 0;
}

2. input函数
用于从文件输入需要解的盘面。

void input(int step)            //step为阶数
{
    int i, j;
    for (i = 0; i < step; i++)
        for (j = 0; j < step; j++)
            cin >> sd[i][j];                //从文件输入sd[i][j]
}

3. output函数
用于向文件输出解出的盘面答案。

void output(int step)           //step为阶数
{
    int i, j;
    for (i = 0; i < step; i++)
    {
        for (j = 0; j < step; j++)
        {
            cout << sd[i][j];           //向文件输出盘面,
            if (j < step - 1)
                cout << " ";
        }
        cout << endl;
    }
    cout << endl;
}

4. check函数
先检测横纵方向是否存在与即将输入的数相同的数,而后检查每一宫内是否存在与即将输入的数相同的数,若存在相同的数则返回,反之返回1。

 int check(int step, int i, int j, int x)           //阶数=step,待填的数横坐标=i,纵坐标=j,待填的数=x
{
    int k, r, c, l;
    for (k = 0; k < step; k++)                  //判断横纵是否存在相同的数
    {
        if (sd[i][k] == x || sd[k][j] == x)
            return 0;                           //存在则返回0
    }
    if (step == 4)                              //判断四宫格内2*2小方格是否存在相同的数
    {
        r = i / 2;
        c = j / 2;
        for (k = r * 2; k < r * 2 + 2; k++)
        {
            for (l = c * 2; l < c * 2 + 2; l++)
                if (sd[k][l] == x)
                    return 0;
        }
    }
    else if (step == 9)                     //判断九宫格内3*3小方格是否存在相同的数
    {
        r = i / 3;
        c = j / 3;
        for (k = r * 3; k < r * 3 + 3; k++)
        {
            for (l = c * 3; l < c * 3 + 3; l++)
                if (sd[k][l] == x)
                    return 0;
        }
    }
    else if (step == 6)                     //判断六宫格内3*2小方格是否存在相同的数
    {
        r = i / 2;
        c = j / 3;
        for (k = r * 2; k < r * 2 + 2; k++)
        {
            for (l = c * 3; l < c * 3 + 3; l++)
                if (sd[k][l] == x)
                    return 0;
        }
    }
    else if (step == 8)                     //判断八宫格内2*4小方格是否存在相同的数
    {
        r = i / 4;
        c = j / 2;
        for (k = r * 4; k < r * 4 + 4; k++)
        {
            for (l = c * 2; l < c * 2 + 2; l++)
                if (sd[k][l] == x)
                    return 0;
        }
    }
    return 1;               //若均不存在则返回1
}

5.build函数
看到题目的第一反应是回溯,但是由于不太熟练就不太想打...打了一个暴力版的三宫格,讨论了几种错误情况,逐渐麻烦...然后回来乖乖打回溯。
首先寻找需要填的空位,若该位置已存在数字,继续向下搜索。发现空位后,调用check函数检验1~9中那个数字填入是合法的,若存在合法的数填充后继续向下搜索填充,反之不存在合法的数则将该位置清零,并回溯。填充完毕时标志位op置1并退出。

int build(int step, int i, int j)
{
    int x;
    if (i > step - 1)               //已填充完毕
    {
        op = 1;                 //标志位置1
        return 0;
    }
    else if (sd[i][j] > 0)                  //该位置已存在数字,填充下一个
    {
        if (j < step - 1)                 //未填充到改行末,继续该行填充
            build(step, i, j + 1);
        else                                //已填充到行末,开始填充下一行
            build(step, i + 1, 0);
    }
    else
    {
        for (x = 1; x <= step; x++)         //尝试填入
        {
            if (check(step, i, j, x) == 1)  
            {
                sd[i][j] = x;               //该数字x未冲突,可以填入
                if (j < step - 1)           //未填充到改行末,继续该行填充
                    build(step, i, j + 1);
                else                           //已填充到行末,开始填充下一行
                    build(step, i + 1, 0);
                if (op == 1)                //标志位已置1,结束
                    return 0;
                sd[i][j] = 0;               //出现冲突,清零
            }
        }
    }
    return 0;
}

6. search0函数
经过build和check函数运行后,若盘面仍有部分格子未被填充,说明题目本身是无解的,将通过search0函数进行查找并报错。

int search0(int step)
{
    int i, j;
    for (i = 0; i < step; i++)
    {
        for (j = 0; j < step; j++)
            if (sd[i][j] == 0)
                return -1;
    }
    return 0;
}

7.主函数

int sd[10][10],op=0;        //全局变量
int main(int argc, char *argv[])
{
    int step = atoi(argv[2]), repeat = atoi(argv[4]);
    FILE *stream1, *stream2;
    freopen_s(&stream1,argv[6], "r", stdin);                //输入重定向
    freopen_s(&stream2,argv[8], "w", stdout);            //输出重定向
    while (repeat--)
    {
        op = 0;
        clear(step);                    //清零
        input(step);                    //从文件输入
        build(step, 0, 0);                 //回缩填充
        if (search0(step) == -1)            //无解题判断
            cout << "error:no answer" << endl << endl;
        else
            output(step);
    }
    fclose(stdin);              //关闭输入文件
    fclose(stdout);            //关闭输出文件
    return 0;
}

- 计算模块接口部分的性能

1791984-20190924221429727-474427268.jpg
1791984-20190923232624461-214807631.png

主要的消耗还是在check和build函数,但是还没想到怎么优化...


- 单元测试

- 3阶,5阶,7阶

1791984-20190924222648589-1745838877.jpg

- 4阶,6阶,8阶

1791984-20190924223117719-774377747.jpg

- 9阶

1791984-20190924223354248-8139975.jpg


- 异常处理

做了一个无解的异常处理...
无解的情况下,build函数调用完毕后,宫图仍保持输入时有空位的情况,调用search0函数进行判断。
1791984-20190924230117168-198784423.jpg


- 心得体会

数独从小就在玩,甚至现在手机里还有app(虽然因为有段时间没开它不兼容了...),但从未站在另一个角度去思考在解数独时会遇到什么?无解?多解?计算机应该怎么去处理这些情况?以后看问题也可以尝试从程序设计的角度去思考,或许会有不一样的发现。
这次实验一开始蛮迷茫的,int main(int argc,char *argv[])、文件输入输出,这些看着熟悉但是并没有用过的东西...文件输入输出本是c语言的内容,但当时这一章被跳过,自己也没有继续去学习。在这次实验中才开始学习,开始尝试寻找适合这次题目的输入方式。
在翻看《构建之法》时看到“这些同学是真的懂软件工程,是一个合格的软件工程师吗?”是啊,我也常常想过去的两年时光究竟学了什么,看似学了很多,却又像什么都不会...许多人都在追求完美,但完美真的存在吗?存在的只有相应时间空间下的“足够好”罢了。

转载于:https://www.cnblogs.com/shan33/p/11575947.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值