递归算法的java实现

目录

一、什么是递归?

二、可以使用递归算法的问题的特点

三、经典的递归问题

1、阶乘,

2、斐波那契数列

3、迷宫问题

4、汉诺塔问题


 活动地址:CSDN21天学习挑战赛

一、什么是递归?

简单来说就是自己调用自己。

递归是一个非常重要的工具,是一些复杂算法的基础。很多著名问题:八皇后问题,树的遍历,斐波那契数列问题,迷宫问题等。需要认真对待。

如下,是一个阶乘的递归调用

/**
 * 阶乘方法
 * 输入一个数n,输出这个数的阶乘
 */
/*
 * 分析思路
 * 1、total = n*...*5*4*3*2*1;
 * 2、a(n) = n * (a(n));
 */
import java.util.Scanner;
public class Recursion {
	public static void main(String[] arg) {
		System.out.println("请输入你要阶乘的数字");
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int a = factorial(n);
		System.out.println(a);
	}
	
	public static int factorial(int n) {
		int total = 1;
		if(n > 1) {        //递归的结束条件
			total = n * factorial(n-1); //递归体if(n > 1) {
		}
		return total;

	}
}

可以看到事实上就是把一个大的阶乘(n!)分成了(n*(n-1)!)

二、可以使用递归算法的问题的特点

1、大的问题可以分成有限数量的子问题,子问题须与原始问题为同样的事,且更为简单;子问题也可以分成有限多个子问题或者极易解决。

2、不能无限制地调用本身,须有个出口,化简为非递归状况处理。

三、经典的递归问题

1、阶乘,

/**
 * 阶乘方法
 * 输入一个数n,输出这个数的阶乘
 */
/*
 * 分析思路
 * 1、total = n*...*5*4*3*2*1;
 * 2、a(n) = n * (a(n));
 */
import java.util.Scanner;
public class Recursion {
	public static void main(String[] arg) {
		System.out.println("请输入你要阶乘的数字");
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int a = factorial(n);
		System.out.println(a);
	}
	
	public static int factorial(int n) {
		int total = 1;
		if(n > 1) {        //递归的结束条件
			total = n * factorial(n-1); //递归体if(n > 1) {
		}
		return total;

	}
}

2、斐波那契数列

/**
 * 斐波那契数列
 * a1=1,a2=1,an=a(n-1)+a(n-2)
 */
/*
 * 思路分析
 * 斐波那契不同于阶乘,他的累进有两部分组成,每部分的累进又可以分成两部分。
 * 累进式为 total = total(n-1) + total(n-2)
 * total作为返回值,则有total = 返回值(n-1) + 返回值(n-2)
 */
import java.util.Scanner;
public class Fibonacci {
	public static void main(String[] arg) {
		System.out.print("n = ");
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int a = fib(n);
		System.out.println(a);
	}

	private static int fib(int n) {
		int total = 0;
		if(n >= 3) {
			total = fib(n - 1) + fib(n - 2);
		}
		else {
			total  = 1;
		}
		return total;
	}
}

3、迷宫问题

迷宫问题

已知一个迷宫如下:

 

 * 1、先创建一个二维数组base作为迷宫的底盘,暂定为7格,定义一个对象mouse
 * 2、规定,用0,1代表地块,0代表可以走,1代表不能走
 * 3、定义一个找路方法findway,它会根据参数判断向哪个方向走
 * 会走到临近的、能走的通的地块,并将该地块标记2表示已走过
 * 4、如果走到死路则回退一格,并将死路上的数字标记为3,表示为死路
 * 5、定义一个走路方法walk,根据当前左边,传递给findway参数,根据findway回传的参数,判断前往那个方向还是回退至上一步
 * 6、胜利条件:出口位置base[5][5]被标记为2
 * 7、为了寻路的高效性,我们规定寻路的优先顺序为下、右、上、左

package Algorithm;
public class MiGong {
	public static void main(String[] arg) {
		int[][] map = new int[7][7];
		for(int i = 0; i < map.length; i++){
        //设立迷宫边界,(另一方面要保证每个小球能到达的位置都有上下左右)
			map[0][i] = 1;
			map[6][i] = 1;
			map[i][0] = 1;
			map[i][6] = 1;
		}
        //设置障碍物
		map[3][1] = 1;
		map[3][2] = 1;
		map[3][3] = 1;
	    //地图的搭建
		System.out.println("====迷宫的地图====");
		for(int i = 0; i<map.length; i++) {
			for(int j = 0; j<map.length; j++) {
				System.out.print(map[i][j]);
			}
			System.out.print("\n");
		}
		//显示地图
		walk(1,1,map);
		
	}
	/**
	 * findway为寻路方法。
     * 通过改变四个方向遍历的优先级可以改变策略形成的路线
	 * findway方法需要接收四个方向参数,并回传下一格的参数x,y
	 * 若四个方向上都不能走,则回传后退参数。
	 */
	public static int[] findway(int down, int right, int up, int lift) {
		int flag = 0;
		int[] next = {0,0};
		if(down == 0) {
			next[0] = 1;
		}
		else if(right == 0) {
			next[1] = 1;
		}
		else if(up == 0) {
			next[0] = -1;
		}
		else if(lift == 0) {
			next[1] = -1;
		}
		return next;
	}
	/**
	 * walk为走路方法,通过递归的方式记录都走了哪些路
	 * 1、接收目前的坐标,并标记3
	 * 2、检查是否已经到达了目的地,若是,则返回真;若否,继续;
	 * 3、传参给findway找路
	 * 4、若找不到路则返回假值
	 * 5、如果有路,则走;但要保留自己这一步的坐标x,y;如果没有路则返回假
	 * 6、若收到下一级返回的假,则继续传参给findway,找到下一条路或者找不到路为止
	 */
	public static boolean walk(int x, int y, int[][] map) {
		
		map[x][y] = 2;
		boolean flag = false;
		int[] direction = {0,0};
		if(map[5][5] == 2){
			return true;
		}
		else {
			do{
				direction = findway(map[x+1][y], map[x][y+1], map[x-1][y], map[x][y-1]);
				if((direction[0] == 0)&&(direction[1] == 0)) {
					return false;
				}
				flag = walk(x+direction[0],y+direction[1],map);
			}while(flag == false);
			System.out.println("("+(x+direction[0])+","+(y+direction[1])+")");
			return true;
		}
	}
}

4、汉诺塔问题

汉诺塔问题是比较典型的递归问题:

相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。

这么说起来比较抽象,我第一次接触汉诺塔问题是在小学课本上,第二次接触是在猩球崛起上。跟黑猩猩比智力 求解汉诺塔问题_哔哩哔哩_bilibili 这一段就是一个非常标准的四阶汉诺塔问题。

 * 递归的特点是回溯,利用回溯,迷宫问题中可以完成死路时的回溯,而在汉诺塔问题中,
 * 则体现在可以分层完成每个圆盘的移动,通过递归移动小一圈的圆盘,通过递归移动大一圈的圆盘。
 * 分析思路:
 * 1、设置三个柱子:起始柱A、辅助柱B、目标柱C,若干圆盘,从小到大依次为1到n
 * 2、输入圆盘数,要求将A柱的圆盘移动到C柱,一次只能移动一个,过程中可以任意使用三根柱子,但是要保证小圆盘始终在上
 * 3、输出每一个圆盘每一步移动的过程,比如:1号圆盘从 A -> C;

 * 编程思路:
 * 1、设置三个int变量a,b,c作为三个柱子,初始化A的柱子有圆盘1到n
 * 2、进入tower函数,从第N层开始:
 * 3、从第N层依次进入到第一层。移动第一层,再以此回溯移动之前的层。
 * 4、先移动第i-1层,再移动自已一层,再移动第i-1层,然后结束溯回i+1层
 * 5、如此循环直到第一层最后一次被移动完毕。

编程的难点之一在于三个柱子身份的转换:

在向下传导的过程中:发生了目标柱与辅助柱的转换;
在完成本层的移动后,发生了起始柱与辅助柱的转换。

能正确理解这两次转换就能理解汉诺塔游戏。

package Algorithm;
/**
 * 汉诺塔:
 * 相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。
 * 该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。
 * 游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。
 * 操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,
 *           操作过程中盘子可以置于A、B、C任一杆上。
 */

import java.util.Scanner;

public class Hanoi {
	public static void main(String[] arg) {
		System.out.println("请输入汉诺塔的层数");
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt();
		char a = 'A';
		char b = 'B';
		char c = 'C';
		tower(num,a,b,c);
	}

	private static void tower(int num, char a, char b, char c) {
		if(num == 1) {
			System.out.println(a+"->"+c);
		}
		else {
			//在传导过程中,需要将辅助柱和目标柱转变身份。
			//因为要想第i层轮盘落在c,那么i-1层就需要将目标柱设置成b
			tower(num -1,a,c,b);
			System.out.println(a+"->"+c);
			tower(num - 1,b,a,c);//交换完i层后,i-1的起始柱就从a变成了b
		}
	}
	
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值