我所知道的算法之递归

做者前言

你们好,我是阿濠,今篇内容跟你们分享的是算法之递归,很高兴分享到segmentfault与你们一块儿学习交流,初次见面请你们多多关照,一块儿学习进步.

1、递归的概念

简单的来讲,递归就是本身调用本身,每次调用时传入不一样的变量,递归有助于编程者解决复杂的问题,同时让本身代码变成简洁算法

2、递归的调用机制

列举两个小案例,认识递归调用机制编程

1.打印问题、2.阶乘问题segmentfault

//1.打印问题
public class RecursionTest {
    public static void main(String[] args) {
        //经过打印问题,回顾递归调用机制
        test(4);
    }
    public static void test(int n) {
        if (n > 2) {
            test(n - 1);
        }
        System.out.println("n=" + n);
    }
}

递归在咱们的程序内部如何调用的?程序从main方法入口进入数组

当咱们进入main方法调用test(4)时,开辟独立空间学习

图片.png

执行test(4)方法时,会有变量n = 4 并进行if判断(4>2),执行test(4-1)方法测试

图片.png

此时执行test(3)方法时,n = 3 也进行if判断(3>2),并执行test(3-1)方法优化

图片.png

此时执行test(2)方法时,n = 2 也进行if判断(2>2),可是2>2 不成立,执行输出指令网站

图片.png

此时test(2)执行完毕后控制台进行输出的结果是 n =2 当test(2)执行完后就退到test(3).. n=三、test(4)... n=4ui

图片.png

图片.png

public class RecursionTest {
    public static void main(String[] args) {
        int res=factorial(3);
        System.out.println("结果="+res);
    }
    //阶乘问题
    public static int factorial(int n) {
        if(n==1){
            return 1;
        } else {
            return factorial(n - 1) * n;
        }
    }
}

按照刚刚示意图的理解,就先是factorial(3 - 1 ) * 3factorial(2 - 1 ) * 2、而factorial(1)直接return 1,因此输出结果就是1 * 2 * 3=6 spa

递归机制小结:

1.当程序执行到一个方法时,就会开辟独立的空间(栈)
2.每一个空间的数据(局部变量),是独立的

递归能够解决什么问题呢?

1.各类数学问题:
如:8皇后问题,汉诺塔,阶乘问题,迷宫问题,球和篮子的问题等等

2.各类算法中也会使用到递归
好比快排,归并排序,二分查找,分治算法等等.

3.将用栈解决的问题-->第归代码比较简洁

递归须要遵照的重要规则

1)执行一个方法时,就建立一个新的受保护的独立空间(栈空间)

2)方法的局部变量是独立的不会相互影响,好比以前举例的 n 变量

3)若是方法中是使用引用变量,即会共享引用类型的数据,即迷宫问题时方法传递是数组,数组是引用类型那么就会进行调用同一个数据:数组

4)递归必须向退出递归的条件逼近,不然就是无限递归,死龟了抛出异常:StackOverflowError

5)当一个方法执行完毕,或者遇到return, 就会返回遵照谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。

递归的实际问题案例

递归-迷宫问题

图片.png

思路分析:

1.建立二维数组模拟迷宫
2.使用1表明墙,上下全是1,便是列在变,行没变,因此范围是0-6在变
3.使用1表明墙,左右全是1,便是行在变,列没变,因此范围是0-7在变
4.使用1表明挡板,即小球没法走到挡板的位置,按图所示第四行的一、2列
5.约定:0 表明没有走过、1 表示墙、2表示路能够走、3已走过但不通
6.按图所示,起点为止从(1,1)开始(第二行第二列),小球在(6,5)的位置
7.若小球为(i,j),向左走是(i,j-1),向右走是(i,j+1),向上走是(i-1,j),向下是(i+1,j)

建立迷宫

//先建立一个二维数组,模拟迷宫地图
int[][] map = new int[8][7];
//使用1表示墙
//上下所有置为1
for (int i = 0; i < 7; i++) {
    map[0][i] = 1;
    map[7][i] = 1;
}
//左右所有置为1
for (int i = 0; i < 8; i++) {
    map[i][0] = 1;
    map[i][6] = 1;
}

//设置挡板, 1表示
map[3][1] = 1;
map[3][2] = 1;

//输出地图
System.out.println("地图的状况");
for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 7; j++) {
        System.out.print(map[i][j] + " ");
    }
    System.out.println();
}

运行结果:
1 1 1 1 1 1 1 
1 0 0 0 0 0 1 
1 0 0 0 0 0 1 
1 1 1 0 0 0 1 
1 0 0 0 0 0 1 
1 0 0 0 0 0 1 
1 0 0 0 0 0 1 
1 1 1 1 1 1 1

找小球策略:下右上左

//使用递归回溯来给小球找路
//说明
//1. map表示地图
//2. i,j 表示从地图的哪一个位置开始出发(1,1)
//3. 若是小球能到map[6][5]位置,则说明通路找到. .
//4. 约定:当map[i][j] 为0表示该点没有走过当为1表示墙; 2表示通路能够走; 3表示该点已经走过,可是走不通
//5. 在走迷宫时,须要肯定-个策略(方法):下->右->上->左 ,若是该点走不通,再回溯
/**
 * @param map 表示地图
 * @param i 从哪一个位置开始找
 * @param j 从哪一个位置开始找
 * @return 若是找到通路,就返回true, 不然返回false
 */
public static boolean setWay(int[][] map, int i, int j) {
    //小球的位置是(6,5) 对应数组则是map[6][5]
    if(map[6][5] == 2) {
        //到map[6][5]位置,说明球已找到
        return true;
    } else {
        //判断到地图map[i][j]是0,则表明这个点尚未走过
        if (map[i][j] == 0) {
            //假设这个点是能够走通的,而后按照策略:下一>右->上->左走
            map[i][j] = 2;
            if (setWay(map, i + 1, j)) {//向下走
                return true;
            } else if (setWay(map, i, j + 1)) { //向右走
                return true;
            } else if (setWay(map, 1 - 1, j)) { //向上
                return true;
            } else if (setWay(map, i, j - 1)) { //向左走
                return true;
            }else {
                //说明该点是走不通,已经走过,是死路
                map[i][j] =3;
                return false;
            }
        } else{
            //若是map[i][j] != 0 ,多是1, 2, 3
            //当为1表示墙; 2表示通路能够走; 3表示该点已经走过
            return false;
        }
    }
}

步骤分析图:

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

.....

递归-八皇后问题

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯●贝瑟尔于1848年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法(92)

八皇后问题算法思路分析.

1.第一个皇后先放第一行第一列
2.第二个皇后放在第二行第一列,而后判断是否0K,若是不OK继续放在第二列、第三列...依次把全部列都放完,找到合适的位置
3.继续第三个皇后仍是第一列、第二列...`直到第八个皇后都放在一个不冲突的位置,算是找到了一个正确解`
4)当获得一个正确解时,栈回退到上一个栈开始回溯,即第一个皇后放到第一列的全部正确解所有获得.
5)而后回头继续把第一个皇后第二列,后面继续循环执行1,2,3的步骤

步骤示意图分析

图片.png

按照思路先将.第一个皇后先放第一行第一列 (小圆圈表明皇后)

图片.png

第二个皇后放在第二行第一列,而后判断是否0K,显然条件是:两个皇后都不能处于同一行、同一列或同一斜线上

图片.png

图片.png

因而第二个皇后再向右移动一个位置,知足条件不是相互攻击

图片.png

因而继续第三个皇后仍是第一列开始,显然条件是:两个皇后都不能处于同一行、同一列或同一斜线上...第...皇后

图片.png

图片.png

图片.png

图片.png

图片.png

图片.png

这时获得一个正确的解就会进行把第一个皇后第二列,后面继续循环执行1,2,3的步骤,可是效率并不高,由于8x8的会执行一万屡次,后面会有算法进行优化

提示说明:

理论上应该建立一个二维数组来表示棋盘,可是实际上能够经过算法用一个一维数组便可解决问题:arr[8]= {0,4, 7,5,2, 6, 1, 3}

arr下标表示第几行,即第几个皇后,arr[i] =val, val表示第i+1个皇后,放在第i+1行的第i+1列

即咱们使用下标表示第几行是第几个皇后,按图所示那么对应的值如果一致则表明在同一列:array[n]==array[i]

图片.png

即咱们使用下标表示第几行是第几个皇后,那么第n个皇后与第n-1皇后的列差 == 第n个皇后与第n-1行差,那么则是同一斜线上:Math.abs(n - i) == Math.abs(array[n] - array[i]),好比说第二个皇后与第一个皇后的行差=一、列差=1,相等证实按图所示它们是斜线

图片.png

实际操做代码以下:

public class Queue8 {

    //定义一个max表示共有多少个皇后
    int max = 8;
    //定义数组array,保存皇后放置位置的结果,好比arr = {0 , 4, 7, 5, 2, 6, 1, 3}
    int[] array = new int[max];
    
    //放置第n个皇后
    public void check(int n){
        //从0开始放置 若n=8 则表明最后一列的皇后了
        if( n == max ){
            printQueue();
            return;
        }
        //依次放入皇后
        for(int i=0; i<max; i++){
            //把当前皇后n,放入第一列位置
            array[n]=i;
            //放入第n个皇后检查是否冲突
            if(judge(n)){
                //若不冲突,则执行n+1个皇后
                check(n+1);
            }
            //若冲突 则继续执行arr[n] = i;即将第n个皇后 放置在本行的后移一个位置
        }

    }

    //查看当咱们放置第n个皇后,就去检测该皇后是否和前面已经摆放的皇后冲突
    /**
     * @param n 表示第n个皇后
     * @return
     */
    private boolean judge(int n) {

        for(int i=0; i<n; i++) {
            //1. array[i] == array[n] 表示判断 第n个皇后是否和前面的n-1个皇后在同一列
            //2. Math.abs(n-i) == Math.abs(array[n] - array[i]) 表示判断第n个皇后是否和第i皇后是否在同一斜线
            //行差=列差 证实是斜线
            if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
                return false;
            }
        }
        return true;
    }

    //写一个方法,能够将皇后摆放的位置输出
    private void printQueue(){

        for (int i = 0; i < array.length; i++) {
            System. out. print(array[i] +"");
        }
        System.out.println();
    }
}

按照思路,添加数据测试一下把

public static void main(String[] args) {
    //测试八皇后
    Queue8 queue8 = new Queue8();
    queue8.check(0);
}

运行结果以下:
04752613
05726314
06357142
06471352
13572064
14602753
14630752
15063724
15720364
16257403
16470352
17502463
20647135
24170635
24175360
24603175
24730615
25147063
25160374
25164073
25307461
25317460
25703641
25704613
25713064
26174035
26175304
27360514
30471625
30475261
31475026
31625704
31625740
31640752
31746025
31750246
35041726
35716024
35720641
36074152
36271405
36415027
36420571
37025164
37046152
37420615
40357162
40731625
40752613
41357206
41362750
41506372
41703625
42057136
42061753
42736051
46027531
46031752
46137025
46152037
46152073
46302751
47302516
47306152
50417263
51602473
51603742
52064713
52073164
52074136
52460317
52470316
52613704
52617403
52630714
53047162
53174602
53602417
53607142
57130642
60275314
61307425
61520374
62057413
62714053
63147025
63175024
64205713
71306425
71420635
72051463
73025164

总共是92种思路解法,发现就是按照思路图的思路进行递归判断,可进入小游戏网站实践一下:http://www.4399.com/flash/426...

相关文章
相关标签/搜索