软件工程第二次作业
1、github链接:https://github.com/laixiaolian/SoftWare
作业链接:https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1715W/homework/866
2、PSP
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 40 | 60 |
· Estimate | · 估计这个任务需要多少时间 | 40 | 60 |
Development | 开发 | 1010 | 1180 |
· Analysis | · 需求分析 (包括学习新技术) | 360 | 400 |
· Design Spec | · 生成设计文档 | 40 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 0 | 0 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
· Design | · 具体设计 | 120 | 120 |
· Coding | · 具体编码 | 360 | 400 |
· Code Review | · 代码复审 | 30 | 20 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 200 |
Reporting | 报告 | 100 | 90 |
· Test Report | · 测试报告 | 30 | 30 |
· Size Measurement | · 计算工作量 | 30 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 40 | 40 |
合计 | 1150 | 1330 |
3、解题思路
刚开始看到这个题目的时候就想可不可以直接直接自己先生成一个数独,然后通过各种变换,生成新的数独,但是想法是有了,却不知道该如何实现(无奈)。于是开始拼命的在网上查找资料,却意外知道了可以用回溯法和置换法。受到网上的启发,又想到了下面这条可行的思路:
- 首先,因为数独是9*9方格,就像是每层都是一个大小为9的一维数组。所以在生成一个数独之前,我先利用随机法生成一个只含有数字1-9的一维数组。利用rand()函数打乱数组中元素存放的位置。
- 之后在生成一个新的数独的时候就可以直接从一维数组中抽取一个元素,然后判断该元素是否已经存在在这一行或者这一列,或者是3*3的九宫格中。如果没有,则说明满足填入的要求,可以将该元素填入该位置,然后对下一个位置进行同样的操作。如果遇到无解的情况,则回溯。
- 当81个格子都已经填满,说明这个数独已经成功生成,可以输出,进而生成下一个数独。
- 在生成下一个数独之前一定要对二维数组初始化,且要重新生成新的一维数组。
4、设计实现过程
- 代码包含一个类,5个函数,分别是init()函数,用于初始化二维数组;initArray()函数,在生成一个数组之前用于生成新的一维数组;generate()函数,用于生成数独;IsRightPlace()函数,用于判断该数字放在这个位置是否合法;print()函数,用于输出数独。
5、代码说明
//每次生成新的数独之前,先生成一个新的一维数组,将数字1-9的顺序打乱
//之后在生成9*9数独的每行时都随机从该一维数组中抽取元素
void SudokuGenerate::initArray()
{
int array[9] = { 0 };
count[11] = { 0 };
int h=0;
for(h=0;h<9;)
{
int temp = rand() % 9;
//判断此次生成的temp是否已经在该一维数组中
if (array[temp] == 0)
{
//因为temp=rand()%9生成的是0-8的随机数,所以要加一
count[h] = temp+1;
//标记这个随机数已经存在在一维数组中。
array[temp] = 1;
h++;
}
}
}
//利用回溯法生成数独
bool SudokuGenerate::generate(int k)
{
int i = k / 9;
int j = k % 9;
if (k == 81)
{
//生成一个数独,打印
print();
cout << endl;
return true;
}
//如果9*9方格中位置(i,j)已经放置了数字
else if (num[i][j] != 0)
{
//生成下一位置的数字
if (generate(k + 1))
{
return true;
}
}
//对空位(i,j)生成数字
else
{
//数独每行的数字从一维数组中随机抽取
for (int l = 1; l <= 9;l++)
{
int temp = rand() % 9;
num[i][j] = count[temp];
//判断填入数字是否合法
if (IsRightPlace(num[i][j], i, j))
{
if (generate(k + 1))
{
return true;
}
}
}
//不合法,则位置(i,j)重置为0,回溯
num[i][j] = 0;
}
return false;
}
//判断填入的数字是否合法
bool SudokuGenerate::IsRightPlace(int number, int row, int col)
{
int temp = number;
//同列不同行中是否存在与之相同的数字
for (int i = 0; i < 9; i++)
{
if (i != row&&num[i][col] == temp)
{
return false;
}
}
//同行不同列行中是否存在与之相同的数字
for (int i = 0; i < 9; i++)
{
if (i != col&&num[row][i] == temp)
{
return false;
}
}
//判断3*3九宫格是否合法
int m = row / 3;
m *= 3;
int n = col / 3;
n *= 3;
for (int i = m; i < m+3; i++)
{
for (int j = n; j < n+3; j++)
{
if (i != row&&j != col&&num[i][j] == temp)
{
return false;
}
}
}
return true;
}
6、测试运行
7、效能分析
n=1000时
- 我们可以看到print()函数使用的次数很多,所以我尝试在print()函数上做一些改变。记得之前老师说过大数据用C输出会相对快一点,尝试了一下,发现确实变快了。
8、单元测试
#include "stdafx.h"
#include "CppUnitTest.h"
#include"..\sudoku\SudokuGenerate.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace SudokuTest
{
TEST_CLASS(UnitTest1)
{
public:
//测试IsRightPlace()函数
TEST_METHOD(TestMethod1)
{
// TODO: 在此输入测试代码
SudokuGenerate sudoku;
//将数独第一行第一列设为3
sudoku.set(3);
//第一行第三列填入数字3,此时应该return false;
bool test1 = sudoku.IsRightPlace(3, 0, 2);
//第三行第一列填入数字3,此时应该return false;
bool test2 = sudoku.IsRightPlace(3, 2, 0);
//第二行第二列填入数字3,此时3*3九宫格中有重复数字,return false;
bool test3 = sudoku.IsRightPlace(3, 1, 1);
//在第二行第七列填入数字3,与三个判断条件都不冲突,return true;
bool test4 = sudoku.IsRightPlace(3, 1, 6);
Assert::IsTrue(test1 == false);
Assert::IsTrue(test2 == false);
Assert::IsTrue(test3 == false);
Assert::IsTrue(test4 == true);
}
};
}
9、总结
- 这次的作业接触到了挺多新的知识,比如效能分析,单元测试。虽然可能对一些知识点还是有些不清楚,但是起码有了初步的了解,自己在这个过程中还是收获颇多的。