软工个人项目之生成和求解数独

本文介绍了作者在软件工程个人项目中实现数独生成和求解的过程,包括生成数独的思路,求解数独的算法,以及性能优化和代码质量分析。作者使用面向对象的C++编写,设计了类和函数,进行了单元测试,并通过性能分析和cppcheck工具改进代码。
摘要由CSDN通过智能技术生成

软工个人项目之生成和求解数独

在这次完成个人项目的过程中,我第一次尝试了写csdn博客,用vs进行性能分析,在vs里面写单元测试,这次收获了很多。虽然还有很多需要改进的地方,但我会做得越来越好的~

1、Github地址

首先给出我的github的地址:
https://github.com/hll455/Project-Sodoku

2、psp表格—估计花费时间

psp2.1 Personal Software Process Stages 预估耗时(分钟)
Planning 计划 30
Estimate 估计这个任务需要多少时间 20
Development 开发 1440
Analysis 需求分析(包括学习新技术) 1000
Design Spec 生成设计文档 40
Design Review 设计复审(和同事审核设计文档) 60
Coding Standard 代码规范(为目前的开发制定合适的规范) 90
Design 具体设计 1200
Coding 具体代码 1200
Code Review 代码复审 600
Test 测试(自我测试、修改代码、修改提交) 1200
Reproting 报告 1200

3、解题思路

1)生成数独

之前对数独没有太多了解,只知道数独每一行每一列每一宫都需要满足1-9不重复。我对生成数独的第一理解,就是相当于对全是0的数独的求解,由于第一行第一个数固定,所以第一行固定排列(一共有8!=40320种),之后开始递归搜索遍历,这样生成到最后一个数字时则生成了数独;生成一个数独之后,可对整个数独进行转置40320✖2=80640,再对2、3行,4、5、6行,7、8、9行交换顺序,这样就可以满足(80640✖2✖6✖6>1000000)。但具体实现时,发现这样的话每生成一个数独的递归求解时,会花费很多时间,在结果的性能评分上肯定不行,所以我就去网上找了一下数独有没有什么简单的规律,比如只需要确定一行,剩下的都可以直接写出来,果然,有一种简单数独就是这样的规律,即:只需要确定第一行,后面的8行都可以通过平移第一行来获得

                                             6 1 2 3 4 5 7 8 9
                                             7 8 9 6 1 2 3 4 5
                                             3 4 5 7 8 9 6 1 2
                                             9 6 1 2 3 4 5 7 8
                                             5 7 8 9 6 1 2 3 4
                                             2 3 4 5 7 8 9 6 1
                                             8 9 6 1 2 3 4 5 7
                                             4 5 7 8 9 6 1 2 3
                                             1 2 3 4 5 7 8 9 6

由上面的数组可以看到,以第一行为基准,9行分别移动的位数为{0,3,6,1,4,7,2,5,8},根据此位移数组,我们可以根据第一行唯一确定一个数独。生成一个数独后,剩余的数独与上面类似,都可以转换成位移数组的位置交换来体现:即3,6可以互换,8,2,5可以互换,7,1,4可以互换,这样可以生成8!✖2✖6✖6=2903040>1000000,符合题目要求。

2)求解数独

我看到求解数独时,思路就是按照我们做数独的思路,当所在位置的数字为0的时候,我们就找这一行、这一列、这一宫有没有1-9中没有出现的数字,有的话则继续往后填写,没有的话则返回上一步,将上一步填写的数字换成另外一个符合要求的数字,依次类推,直到数独中的最后一个0被填充完成,则求解成功。这样的话,只需要递归求解就好,不过如果每次对一个0的那一行那一宫那一列遍历的话,时间复杂度会很高,所以我采取“以空间换时间”,对数独进行预处理,直接将行列宫的数字出现与否用数组表示出来,这样,在每次判断是否可以填入某数时,则不需要进行遍历,只需要直接查看该数组的某一个元素的值是否为0。这里我设置了一个三维数组大小为visit[3][10][10]的数组,利用每个元素的值来表示该宫/行/列中的某个数字是否出现过,0为未出现,1为出现。visit数组第一维中0表示宫,1表示行,2表示列,第二维中表示第几行/第几列/第几宫(范围为0到9),第三维表示1-9数字。

4、设计实现过程

1)类与函数及函数间关系

其实最开始写的代码为面向过程的c语言,后来因为单元测试需要类,所以我将面向过程直接改成了面向对象的c++。
只设置了一个类sodoku,将输入的两个参数作为属性;
主要设置了三个函数,其中choosecors函数对solvesodoku和createsodoku函数进行调用。

  • choosecors函数——对输入的参数进行处理,

  • createsodoku函数——生成数独,

  • solvesodoku——求解数独。

    流程图如下所示:

输入'-s'
输入'-c'
choosecors函数
预处理
solovesodoku函数
createsodoku函数
写入文件

2)单元测试的设计

我设计了10个测试用例,其中5个检查生成数独时输入参数的合法性,1个测试非-s和-c的输入的处理,2个测试求解数独的正确性和格式的正确性,2个检查生成数独时输入参数的合法性。完成对所有路径的测试,除了输入时的参数个数问题不能在单元测试中体现。
十个测试用例分别为:其中choosecors函数的输入参数分别为argv[1]和argv[2]

1int ans = s1.choosecors("-c", "a");
2int ans = s1.choosecors("-c", "1000001");
3int ans = s1.choosecors("-c", "123");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值