性能分析
生成总局
生成1000000个数独时的性能分析图:
查看函数消耗情况:
由于在编码时已经采用了比较节省时间的方式,比如把第一行的40320种情况全都预先储存起来,以及在各行交换生成多种终局时手动记录下要交换的行的索引,因此生成一百万个数独终局累计耗费17余秒,已经算是不错的结果。目前通过性能分析图可以看到,主要的时间花费在了写入文件的的fprintf函数上,因此考虑对此进行优化。首先我想到的是将逐个输出改为一次输出一整行的形式,即由
for (int j = 0; j < 9; j++)
{
if (j == 0)
fprintf(fp, "%d", grid.map[i][j]);
else
fprintf(fp, "%c%d", ' ', grid.map[i][j]);
}
改为
fprintf(fp, "%d %d %d %d %d %d %d %d %d\n", grid.map[i][0], grid.map[i][1], grid.map[i][2], grid.map[i][3], grid.map[i][4], grid.map[i][5], grid.map[i][6], grid.map[i][7], grid.map[i][8]);
后经测试效率确实有了一些提升,但是这时我又了解到fwrite函数,由于其是以二进制的形式对文件进行操作,效率比fprintf要高很多,于是我打算改用fwrite进行写入文件。
于是代码变为:
for (int j = 0; j < 9; j++)
{
char temp=(grid.map[i][j]+'0');//将整型转为字符型以便用fwrite输出
if (j == 0)
fwrite(&temp, 1, 1, fp);
else
{
fputc(' ',fp);
fwrite(&temp, 1, 1, fp);
}
}
效果提升明显,改进后的性能情况如下:
可以看到,采用了fwrite函数对输出进行优化之后,效率提升了近三倍,仅6秒多就完成了生成一百万个数独终局的任务。
求解数独
求解1000000个数独题目耗时如下:
由于在编码时已经采用了较为高效率的方式,比如在检查行/列/宫中的数字时采用位运算来加快速度,以及进行DFS操作时采用指针引用技术来避免内存复制而导致的低效率问题,所以可以看到解1000000个数独题目耗时约两分钟,主要花费时间在DFS上,这里毕竟算法复杂度在那摆着呢,也没办法再有什么很大的提升了。
未来方向
在生成终局部分仍然是写入文件的函数消耗了大多数的时间,但fwrite毕竟是系统函数,难以进行优化,后续或许可以考虑尝试由操作系统提供的文件操作API进行读写操作以将速度进一步提升。
在求解数独部分DFS算法消耗了大多数的时间,若对其进行优化就应当考虑采用更高效率的算法诸如舞蹈链等。
另外读文件的部分也可以进行再优化。