【C数据结构与算法】递归调用经典例题:八皇后问题

    刚刚学习了递归调用的知识,觉得递归这种算法真是太妙了。

    递归算法:优点:定义清晰,容易证明其正确性和完备性;

                     缺点:1、资源消耗大;一个最简单的递归,其每次调用都至少消耗8B空间(这里是关于形参实参值传递的问题,详细可以参考本人的第一篇博客,https://blog.csdn.net/weixin_41978722/article/details/79921816#0-qzone-1-39788-d020d2d2a4e8d1a374a433f596ad1440),若不控制其递归深度,就很容易造成系统堆栈的溢出,使系统崩溃。

                                2、会出现大量重复运算。(如斐波那契数列:

                                                                            int fibonacci(int n) {

                                                                                return n<=2? 1:fibonacci(n-2)+fibonacci(n-1);     }        )


    下面,通过一例题来表现一下递归算法:八皇后问题。

    根据所学,递归要考虑  1.相同操作   2.思考简单  3.递归结束条件


    看到问题,不要急于编程,“手工过程”很重要!如果我们面前有一个棋盘,我们要怎样摆?


    1、按照一般人的思维,一行一行来;第一个皇后放到第一行第一列上(1,1),下一个皇后必然在第二行放置,放置同样从第一列开始考虑,直到该棋子安全(其左上,上,右上方向均无棋子),则开始下一行;

    2、若这一行没有安全位置,就必须返回上一行,继续移动上一行的棋子找到该棋子下一个安全位置,以此类推;

    3、结束条件:找到最后一行的安全位置,即第8行,结束!

    所以每次递归操作只需考虑此时自己这一行就好!


    那么,棋盘如何表示?        二维数组!   8*8方阵,咱们用1代表放置棋子,0代表没有放置棋子。


    程序主要函数如下:

    

void orderQueen(int (*chessboard)[8], const int row) 	  // 在当前行只需要考虑当前行!
{	
	if (row >= 8) 
	{
		drawChessboard(chessboard);
	} else {
		int col;
		
		for (col = 0; col < 8; col++) // 尝试每一列
		{ 
			chessboard[row][col] = 1;		// 放置皇后
			if (isSafe(chessboard, row, col)) // 若本行本列是安全的
			{ 
				orderQueen(chessboard, row + 1); // 放置下一行
			}
			chessboard[row][col] = 0;		// 无论本行列是安全或者不安全的,都需要去掉本位置的皇后!因为,下列需要放置一个皇后!
		}
	}
}

void drawChessboard(int (*chessboard)[8]) 
{
	int row;
	int col;
	static int count = 0;
	
	printf("第%d个解:\n", ++count);
	for(row = 0; row < 8; row++)      //输出棋盘
	{
		for(col = 0; col < 8; col++) 
		{
			printf("%2d", chessboard[row][col]);
		}
		printf("\n");
	}
}
	
int isSafe(int (*chessboard)[8], const int row, const int col) 
{
	int i;
	int j;
	
	for (i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--)    //判断左上方向有无棋子
	{
		if (chessboard[i][j] == 1) 
		{
			return 0;
		}
	}
	for (i = row - 1, j = col; i >= 0; i--)                       //判断上方有无棋子
	{            
		if (chessboard[i][j] == 1) 
		{
			return 0;
		}
	}
	for(i = row - 1, j = col + 1; i >= 0 && j < 8; i--, j++)     //判断右上方有无棋子
	{
		if (chessboard[i][j] == 1) 
		{
			return 0;
		}
	}
	
	return 1;    
}
    如果无法理解此行判断完没有安全位置返回上一行操作的,怎么说呢?通俗点说递归他是一层套一层的,如果这层判断完自然就回到了上一层,若还是没有理解,可能在我表述不清;建议自己画棋盘用棋子对照程序 变量跟踪 ,这就很好理解了!
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务