好久没写过程序了。再慢慢找回那种感觉吧。这个程序其中一些地方也许设计不当,权当解数独的一个参考。
数个小时的专注工作,终于写出了数独的一个C语言程序。由于许久没有编写过程序了,中间经历了许多的困难,虽然程序的质量还有待改进,但总体运行还是达到了要求。
先总结下思路与问题,留待以后改进。
1、用的版本是C-Free 5.0专业版
2、思路是深度优先搜索
3、递归中的return不是结束整个递归,只是结束本次调用,返回到上一级
调试过程:
出现问题时首先根据结果思考原因,之后可在程序的关键位置处显示特殊标记符号的或一些变量的值来提示程序的执行情况。
再者可一步步的单步调试,实时的查看相应内存的情况。(首先的一个问题是我怎么知道某些量的内存,)
此时显示的只是此函数内的局部变量的数据情况,查看全局变量等需先找到该全局变量的内存地址(或执行到该语句时点击到内存中查看也可知道内存地址)。可通过设置指向该变量的指针。原理同该数组。
可知道数组possiblenum[NUM]的地址为0x22fef0,在内存中输入此地址即可查看。
例如把数组的第一个数修改为5,结果如图所示。
下图所示情况为,要填的数超过一定量时会出错(与要填的数的位置也有关,出错的原因在下面。)
填完最后一个空后,if语句为真,调用显示函数。之后返回上一级递归。因为shudu[][]相当于全局变量,此次的调用修改了shudu[][]中的值。返回上一级的时候,shudu[][]不是一开始执行该此调用时的值了。故会导致出错。(局部变量不会受影响,因已经入栈。)
所以下面应该加上一句,使之保持原样。(注意理解透彻)递归返回时会返回到产生递归的地方,之后顺序执行下面的语句。
注意与这样的递归结合分析
这是用递归求解n!的算法。
对于递归,首先需要结束递归的条件,如上面的递归到n==0,因为这个需要上级递归后求得的值,所以需要返回给下一级,最终的返回值即是所求解的值。
具体的可以分析下汉诺塔游戏,很经典。
数独这个解法的具体思路是:
首先找到要填的第一个位置,然后判断这个位置可以填入哪些数据,然后填入一个数据,再找下一个位置,重复上述过程。若是当前位置没有可以填入的数据,则返回上一层,填另一个数。再继续。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#define NUM 9
char findposition(int shudu[][NUM],char *xlable,char *ylable)//找到要填的位置 ,起始坐标(0,0) ,成功返回0
{
char i,j;
for(i=0;i<NUM;i++)
{
for(j=0;j<NUM;j++)
{
if(shudu[i][j]==0)
{
*xlable=i;
*ylable=j;
return 0;
}
}
}
return 1;
}
void findpossiblenum(int shudu[][NUM],char xlable,char ylable,int *possiblenum)//该位置所有可能的值 ,所有的值放在一个数组中
{
char i,j,k=0;
//先判断行
for(i=0;i<NUM;i++)
{
if(shudu[xlable][i])
*(possiblenum+shudu[xlable][i]-1)=0;//判断下是否指向了数组的该位置
}
//判断列
for(i=0;i<NUM;i++)
{
if(shudu[i][ylable])
*(possiblenum+shudu[i][ylable]-1)=0;//判断下是否指向了数组的该位置
}
//判断小数独
for(i=(xlable/3)*3;i<(xlable/3)*3+3;i++)
for(j=(ylable/3)*3;j<(ylable/3)*3+3;j++)
{
if(shudu[i][j])
*(possiblenum+shudu[i][j]-1)=0;
}
}
void display(int shudu[][NUM])
{
int i=0,j=0;
for(i=0;i<NUM;i++)
{
for(j=0;j<NUM;j++)
{
printf("%d",shudu[i][j]);
putchar(' ');
}
putchar('\n');
}
}
void solveshudu(int shudu[][NUM])//求解
{
int possiblenum[9]={
1,2,3,4,5,6,7,8,9
};//用于存放所有可能的值
char i;
char xlable=0;
char ylable=0;
int *p=&possiblenum[0];
if ( findposition(shudu,&xlable,&ylable) )
{
display(shudu);
// getchar(); //暂停程序
}
else
{
findpossiblenum(shudu,xlable,ylable,p);
for(i=0;i<NUM;i++)
{
if(possiblenum[i])
{
shudu[xlable][ylable]=possiblenum[i];
solveshudu(shudu);
shudu[xlable][ylable]=0;
}
}
}
}
int main()
{
int i,j;
int shudu[NUM][NUM]={
{3 ,0 ,5 ,7, 0 ,4 ,8 ,6, 1},
{4, 8 ,0, 1, 6, 3 ,9 ,5 ,2},
{6 ,2, 1, 0 ,8 ,0 ,3, 7, 4},
{9 ,0 ,2 ,5 ,0, 8, 6 ,3 ,7},
{5 ,6 ,8 ,2, 3, 7, 4 ,1 ,9},
{7, 0, 3, 0 ,9, 0, 0, 2 ,0},
{2, 0, 9 ,8 ,0, 0, 0, 0, 6},
{8, 0, 6 ,3 ,0, 2, 1, 9 ,5},
{1, 5, 4, 0 ,7, 9 ,2, 8, 3}
};
/* while(scanf("%d",&shudu[0][0]) != EOF)//这个是用于多次输入数独求解的
{
for(i=0;i<NUM;i++)
{
for(j=0;j<NUM;j++)
{
if(i==0&&j==0)
{
j++;
printf("%d",shudu[0][0]);
}
scanf("%d",&shudu[i][j]);
}
}
solveshudu(shudu);
}*/
solveshudu(shudu);
return 0;
}