• 八皇后问题——递归精讲


    我们先来实现一个非常熟悉的递归操作——阶乘
    那么,不需要多说,相信好多同学都会想到如下代码:

    int factorial(int n) {
    	if(n<0) {
    		return -1;
    	}
    	
    	return n == 0 ? 1 factorial(n-1);
    }
    

    我们再来复习一个曾经学习C的时候编写过的一个程序——兔子繁殖问题(斐波那契额数列)
    代码如下:

    int Fibonacci(int n) {
    	if(n<0) {
    		return -1;
    	}
    
    	return n <= 2 ? 1 : Fibonacci(n-1) + Fibonacci(n-2);
    }
    

    那么,复习了递归的一些函数,我们现在来总结一下递归的优缺点:

    优点:

    数学定义清晰,容易证明算法的正确性和完备性

    缺点:

    1.系统资源消耗大,每次函数的调用,都要消耗8B空间(若不控制递归的深度,则很容易在造成“堆栈溢出”,造成程序崩溃);
    2.会出现大量重复计算。

    现在我们就进入我们今天的主题——八皇后问题
    那么,什么是八皇后问题呢?

    八皇后问题:

    在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后不能处于同一行同一列同一斜线上

    首先,有两个函数需事先实现:
    1.输出一个棋盘(包括其中的“后”);
    国际象棋盘该如何实现?
    二维数组,棋盘本来就是一个8*8的二维数组
    所以,代码如下:

    void drawChseeboard(int (*chessboard)[ORDER]) {
    	int row;
    	int col; 
    	static int count = 0;				//static 类型的变量不会随着函数的调用而申请新的空间
    	
    	printf("第%d个解:
    ", ++count);
    	for(row = 0; row < ORDER; row++) {
    		for(row = 0; row < ORDER; row++) {
    			printf("%4d", chessboard[row][col]);
    		}
    		printf("
    ");
    	}
    	printf("
    ");
    }
    

    2.检测本行、本列是否安全:
    这个函数相对简单,所以我们就不再进行详细的解释了,代码段如下:

    boolean isSafe(int (*chessboard)[ORDER], 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 FALSE;
    		}
    	}
    
    	for (i == row - 1, j = col; i >= 0; i--) {	//向上方探寻
    		if (chessboard[i][j] == 1) {
    			return FALSE;
    		}
    	}
    
    	for (i == row - 1, j = col + 1; i >= 0 && j < ORDER; i--, j++) {	//向右上方探查
    		if (chessboard[i][j] == 1) {
    			return FALSE;
    		}
    	}
    
    	return TRUE;
    }
    

    那么,接下来就是我们最关键的部分了——放置皇后函数:

    void orderQueen(int (*chessboard)[ORDER], const int row) {
    	int col;
    	static boolean success = FALSE;
    
    	//在当前行行号已经时ORDER,意味着,前面的ORDER行已经成功!
    	if(!success && row == ORDER) {
    		success = TRUE;
    		drawChseeboard(chessboard);
    	} else {
    		for (col = 0; !success && col < ORDER; col++) {
    			chessboard[row][col] = 1;			//放置皇后
    			if(isSafe(chessboard, row, col)) {  //若本行本列是安全的
    				orderQueen(chessboard, row+1);  //放置下一行
    			}
    			chessboard[row][col] = 0;			//去掉本位置的皇后(无论本行安全不安全)
    		}										//因为,下列需要放置一个皇后!
    	}
    }
    

    那么,现在我们来总结下我们编写的文件:
    mec.h:

    #ifndef _MEC_H_
    #define _MEC_H_
    
    typedef unsigned char boolean;
    
    #define TRUE  1
    #define FALSE 0
    
    #endif
    

    eightQueen.h:

    #ifndef _EIGHT_QUEEN_H_
    #define _EIGHT_QUEEN_H_
    
    #include "mec.h"
    
    #define ORDER 8
    
    boolean isSafe(int (*chessboard)[ORDER], const int row, const int col);
    void drawChseeboard(int (*chessboard)[ORDER]);
    void orderQueen(int (*chessboard)[ORDER], const int row);
    #endif
    

    eightQueen.c:

    #include <stdio.h>
    
    #include "eightQueen.h"
    
    
    void orderQueen(int (*chessboard)[ORDER], const int row) {
    	int col;
    	static boolean success = FALSE;
    	
    	if(!success && row == ORDER) {
    		success = TRUE;
    		drawChseeboard(chessboard);
    	} else {
    		for (col = 0; !success && col < ORDER; col++) {
    			chessboard[row][col] = 1;			
    			if(isSafe(chessboard, row, col)) {  
    				orderQueen(chessboard, row+1);  
    			}
    			chessboard[row][col] = 0;			
    		}										
    	}
    }
    
    void drawChseeboard(int (*chessboard)[ORDER]) {
    	int row;
    	int col; 
    	static int count = 0;	
    											
    
    	printf("第%d个解:
    ", ++count);
    	for(row = 0; row < ORDER; row++) {
    		for(row = 0; row < ORDER; row++) {
    			printf("%4d", chessboard[row][col]);
    		}
    		printf("
    ");
    	}
    	printf("
    ");
    }
    
    boolean isSafe(int (*chessboard)[ORDER], 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 FALSE;
    		}
    	}
    
    	for (i == row - 1, j = col; i >= 0; i--) {	
    		if (chessboard[i][j] == 1) {
    			return FALSE;
    		}
    	}
    
    	for (i == row - 1, j = col + 1; i >= 0 && j < ORDER; i--, j++) {	
    		if (chessboard[i][j] == 1) {方
    			return FALSE;
    		}
    	}
    
    	return TRUE;
    }
    

    还有就是我们调用这些函数的主函数了:
    test.c:

    #include <stdio.h>
    
    #include "eightQueen.h"
    
    int main() {
    	int chess[ORDER][ORDER] = {0};
    
    	orderQueen(chess, 1);
    
    	return 0;
    }
    

    我们想要运行上述代码,还是需要我们数据结构与算法专栏一直都在强调的“运用命令行或者虚拟机进行多文件联编”的方法。

    至于递归运算,我们一定要进行手动的变量跟踪,递归调用的操作十分单纯,但是在我们一直递归的过程中,就可能使得逻辑看起来十分复杂,这时候就需要我们进行变量跟踪了。

    编程的学习是戒骄戒躁的,若是我们不能平静心境取学习,那么,我们就很可能产生一些难以解决的问题,所以,在数据结构的学习中,我们要渐渐使得心境平和,并且在学习算法的过程中能够受到启发,我认为,这就是我们学这门课的主要目的了。

  • 相关阅读:
    [LeetCode] 222. Count Complete Tree Nodes Java
    [LeetCode] 199. Binary Tree Right Side View Java
    自动加载的两种办法
    Cannot switch on a value of type String for source level below 1.7. Only convertible int values or enum variables are permitted
    Java 面试
    Java 获取最近时间
    Java 倒序输出
    java 排序算法
    图片预览
    SSH三大框架的工作原理
  • 原文地址:https://www.cnblogs.com/codderYouzg/p/12411970.html
Copyright © 2020-2023  润新知