单人项目

Github工程链接

  • 命令行程序 https://github.com/YoungForest/Sudoku-Cli
  • GUI附加题 https://github.com/YoungForest/Sudoku-GUI

PSP表

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划2030
Estimate估计这个任务需要多少时间1010
Analysis需求分析3020
Design具体设计6050
Design Spec生成设计文档6060
Coding Standard代码规范3020
Development开发300400
Code Review代码复审4045
Test测试200250
Reporting报告6050
Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划3030
合计840965

熟悉Visual Studio 2017

单元测试

助教@ChildishChange推荐的示例跳跃性太强,很多关键步骤没有截图或截图不完整,且是中文版的Visual Studio。使我这样的初学者很迷惑。

所以我选择了参考官方的测试文档。不得不说,巨硬家的文档写的就是好,
有图有真相。

单元测试还是及其好用的。上次大规模使用单元测试应该是大二下的“面向对象建模方法(OO)”的实验课了,当时的单元测试的工具是Eclipse + JAVA,并没有深度使用。单元测试的好处有很多。我现在有感受的主要有:改动代码后仍然能很方便地保证功能的正确性;测试甚至调试某一方法或函数很方便(我之前都是新建一个小工程进行测试和调试,有了单元测试这些都不需要了)。

生成数独

设计详述

我定义了一个数独格子的类,维护格子中的数和填格子的操作。首先,将数独的左上角填成5;之后,递归地从左到右填充格子;对于每一个格子,我们先生成一个包含1到9的随机列表,所填的数就是依次选取这个列表中的数。之所以这么做,是为了增加生成数独的随机性。每填一个数,判断其是否符合与行列小宫格中数不同的 要求。如果满足,判断是否数独已经填完。如果数独生成完毕,打印这个数独,并在最后一个格子上尝试下一个数;如果没填完,则继续填下一个格子。如果不满足,尝试列表中的下一个数。直到列表尝试完毕,返回上一个格子,并在上一个格子选取列表中的下一个数。

当生成了足够多的数独后,直接抛出一个异常,中断生成数独的递归程序,简单暴力。

我生成数独的算法使用的是最简单暴力的搜索法,时间复杂度很高,因为有回溯过程中有大量碰撞的情况。不过实现起来比较简单。
其实生成1000,000个数独有更取巧的方法。题目要求生成数独不重复,但并没有要求通过旋转、对称、置换、行交换、列交换等操作后仍不重复;而且通过阅读乾神的测试程序,我发现判断两个数独是否相等只是判断了两个数独的HASH值是否相等,并没有防范对称、旋转、置换后的数据不重复。

那么,一个数独通过旋转、对称、置换后可以产生多少数独呢?由于我们将左上角的数字定死了,旋转就不可以了,对称只能是从左上角到右下角的对角线对称,置换也只能是8个数字之间的置换。所以,大概会产生2! * 3! * 3! * 2! * 3! * 3! * 2 * !8 = 474656个数独。为了保证数独生成的不重复性,我们可以使用HashSet来维护。

性能分析

首次运行时的效能分析

由效能分析结果可知,花费CPU时间最多的两个内部调用是 数独生成器的FillNextGrid和PrintResult。其中,FillNextGrid是递归搜索数独结果的函数,由于搜索空间大,所需CPU时间多;PrintResult是当搜索到一个正确的数独时,打印结果到文件中去。针对这效能低下两个函数,可以由以下改进:

如何缩小搜索空间?我们可以采用生成等价数独的方法。即搜索到一个数独后,通过交换行列、数字置换、对称等方式生成与之等价却不相等的数独。由于一个数独可以生成等价数独的数目是巨大的,这样做可以有效地缩小搜索空间。当然,这种方法也有弊端:丧失了很大的随机性,产生的数独大量相关。

如何减少输出所需的时间?输出作为一种IO操作,相比CPU来说确实是很慢的。在CPU的效能分析中,输出结果函数同样占用了很多CPU时间,可能是调度等待的时间比较长。为了提升IO操作,我想到两种方法:一是多线程,计算和IO分离;二是先将结果存在一个数据结构(内存)中,累积到一定量时再一同输出。两者同时作用效果当然更好(其实是我不会用C#的多线程编程)。

求解数独

我求解数独的方法和生成数独很类似,都是使用回溯法。区别在于,生成数独时判断数字不重复只需要和左边还有上边的格子比较,求解时就还要比较了。同样存在时间复杂度较大的问题。

附加题 GUI

附加题没有算法上的难度,更多是是工程和实践上;包括错误处理,交互设计等。生成数独可以调用与CLI相同的库,增加按规定随机挖空的功能;用户填完数独提交后,还需要判断所填数独的正确性,给出相应的反馈。

我实现GUI用的是WPF(Windows Presentation Foundation),Visual Studio对其的支持非常好,开发效率也极高。我之前接触过一点UWP的开发,并没有WPF开发的经验。但是UWP开发出的程序无法生成可执行程序,不符合需求,只能生成安装包,助教测试的时候还要安装,很不方便。WPF的界面设计语言与UWP很像都是xaml的,所以之前的经验还是很有用的。

感想体会

在群里看到有些大佬使用QT完成GUI,而我用的WPF;而且大多数人使用C++完成这次作业,而我用的C#。看来我使用的工具和语言都比较小众。很多同学生成时间都比我快很多,1M的数独只需要几秒。看来我程序和算法还有很大的提高空间。

转载于:https://www.cnblogs.com/YoungForest/p/7594334.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值