【Java复健指南03】递归思想
【递归】
递归重要规则
1.执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
方法的局部变量是独立的,不会相互影响,比如n变量
如果方法中使用的是引用类型变量(比如数组,对象),就会共享该引用类型的数据.
递归必须向退出递归的条件逼近,否则就是无限递归,出现栈溢出(StackOverflowError)
当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。
演示
public class Recursion01{
public static void main(String[] agrs){
T t1 = new T();
t1.test(4);
int res = t1.factorial(5);
System.out.println("res="+res);
}
}
class T {
/*
每次递归调用后会在栈中生成一个新的空间
当条件不满足之后,从栈顶往下返回值,每次返回都会把方法体的代码(在这里是"打印n")都执行一遍
所以最后的执行结果是
n = 2
n = 3
n = 4
*/
public void test(int n){
if(n > 2){
test(n - 1);
}
System.out.println("n="+n);
}
//factorial 阶乘
/*
*/
public int factorial(int n) {
if (n == 1) {
return 1;
}else {
return factorial(n - 1) * n;
}
}
}
练习
习题一 给出对应位置的斐波那契数
请使用递归的方式求出斐波那契数1,1,2,3,5,8,13.….给你一个整数n,求出它的值是多少?
思路:
1.当n=1斐波那契数是1
2.当n=2斐波那契数是1
3.当n>=3斐波那契数是前两个数的和
4.这里就是一个递归的思想
public class RecursionExercise01{
public static void main(String[] agrs){
T t1 = new T();
int n = 7;
int res = t1.fibonacci(n);
if(res ! = -1){
System.out.println("n="+ n +" 对应的斐波那契数=" + res);
}
}
}
class T {
public int fibonacci(int n){
//若不满足条件,则这两个数肯定是1,直接返回即可
if(n >= 1){
if(n == 1 || n == 2){
return 1;
}else{//当n>=3斐波那契数是前两个数的和,思想有点类似阶乘问题
return fibonacci(n-1) + fibonacci(n-2);
}
}else {
System.out.println("输入的整数n需要大于等于1");
return -1;
}
}
}
习题二 逆推思想与递归(猴子吃桃问题)
猴子吃桃子问题
有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个1以后每天猴子都吃其中的一半,然后再多吃一个。
当到第10天时,想再吃时(即还没吃)发现只有1个桃子了。
问题:最初共多少个桃子?(即第一天有多少桃子)
思路 逆推
1. day = 10时有1个桃子
2. day = 9时有(day10 + 1)* 2 = 4
3. day = 8时有(day9 + 1)* 2 = 10
4. 规律就是,前一天的桃子=(后一天的桃子+1)*2
5. 递归
public class RecursionExercise01{
public static void main(String[] agrs){
T t1 = new T();
// int n = 7;
// int res = t1.fibonacci(n);
// if(res != -1){
// System.out.println("n="+ n +" 对应的斐波那契数=" + res);
// }
//桃子
int day = 9;
int peachNum = t1.peach(day);
if(peachNum != -1){
System.out.println("第"+day+"天有"+ peachNum +"个桃子");
}
}
}
class T {
public int peach(int day){
if(day == 10){//第10天只有1个桃子
return 1;
}else if(day >= 1 && day <= 9){//规律要自己寻找
return(peach(day + 1)+1) * 2;
}else {
System.out.println("day的范围是1~10");
return -1;
}
}
}
习题三 递归与回溯机制(老鼠走迷宫)
老鼠走迷宫

有一个迷宫(即一个正方形二维数组map[] []),其中使用1代表边界障碍
右下角为迷宫出口(假设为map[6] [5])
找出走到出口的路线
解法
public class MiGong{
public static void main(String[] agrs){
//思路
//1.先创建迷宫,用二维数组表示
//2.先规定map数组的元素值:0表示可以走1表示障碍物
int[][] map = new int[8][7];
//3.将最上面的一行和最下面的一行,全部设置为1
for(int i = 0; i< 7; i++){
map[0][i]= 1;
map[7][i]= 1;
}
//4.将最右面的一列和最左面的一列全部置为1
for(int i = 0; i< 7; i++){
map[i][0]= 1;
map[i][6]= 1;
}
//单独设置障碍物
map[3][1] = 1;
map[3][2] = 1;
//测试回溯机制
map[2][2] = 1;
//输出当前地图
System.out.println("=====当前地图情况=====");
for(int i = 0; i<map.length;i++){
for(int j = 0; j<map[i].length; j++){
System.out.print(map[i][j] + " ");
}
System.out.println("");
}
//使用findWay给老鼠找路
T t1 = new T();
t1.findWay(map, 1, 1);//初始位置1,1
// t1.findWay2(map, 1, 1);//初始位置1,1
System.out.println("\n=====找路的情况=====");
for(int i = 0; i<map.length;i++){
for(int j = 0; j<map[i].length; j++){
System.out.print(map[i][j] + " ");
}
System.out.println("");
}
}
}
class T{
// 使用递归回溯的思想来解决老鼠出迷宫
//1. findway方法就是专内来找出迷宫的路径
//2. 如果找到,就返回true ,否则返回false
//3. map就是二维数组,即表示迷宫
//4. i,j就是老鼠的位置,初始化的位置为(1,1)
//5.因为我们是递归的找路,所以我先规定 map数组的各个值的含义
// 0表示可以走1表示障碍物2表示可以走 3表示走过,但是走不通是死路
//6.当map[6][5] = 2就说明找到通路,就可以结束,否则就继续找-
//7.先确定老鼠找路策略下->右->上->左
public boolean findWay(int[][] map, int i, int j){
//关键点1:递归退出条件
if(map[6][5] == 2){//说明找到出路
return true;
}else {
if(map[i][j] == 0){//当前这个位置0,说明可以走
//那么可以给当前位置一个假定值2(假设可以走通)
map[i][j] = 2;
//关键点2:寻路策略
//然后根据找路策略来确定该位置是否真的可以走通
//下->右->上->左
if(findWay(map, i + 1, j)){//下
return true;
}else if(findWay(map, i, j + 1)){//右
return true;
}else if (findWay(map, i - 1, j)) {//上
return true;
}else if (findWay(map, i, j - 1)) {//左
return true;
}else {
//所有方向都走不通那说明最开始的假设是错的
//那么把当前位置赋值为3并返回false
map[i][j] = 3;
return false;
}
}else {//不为0就只有三种情况,1,2,3
return false;
}
}
}
//改变寻路策略,下右上左->上右下左
public boolean findWay2(int[][] map, int i, int j){
//关键点1:递归退出条件
if(map[6][5] == 2){//说明找到出路
return true;
}else {
if(map[i][j] == 0){//当前这个位置0,说明可以走
//那么可以给当前位置一个假定值2(假设可以走通)
map[i][j] = 2;
//关键点2:寻路策略
//然后根据找路策略来确定该位置是否真的可以走通
//下->右->上->左
if(findWay2(map, i - 1, j)){//上
return true;
}else if(findWay2(map, i, j + 1)){//右
return true;
}else if (findWay2(map, i + 1, j)) {//上
return true;
}else if (findWay2(map, i, j - 1)) {//左
return true;
}else {
//所有方向都走不通那说明最开始的假设是错的
//那么把当前位置赋值为3并返回false
map[i][j] = 3;
return false;
}
}else {//不为0就只有三种情况,1,2,3
return false;
}
}
}
}
注意点:
所谓的“回溯机制”,就是递归条件达成之后,栈从最顶端往后返回值的过程实现的
在这个问题中体现为,如果“老鼠”走出下一步之后,判定上下左右均不可走,那么会把当前位置标注为3,即不可走
然后会回到上一步的位置,接着判断下一个位置是否能走(因为上一个位置只是选中了一个可以走的方向,其他的还没有判断)
习题四 汉诺塔
汉诺塔问题

即有三个柱子,第一个柱子上有一些从大到小往上摞的圆盘
现在需要将这些圆盘全部移动到最右边的柱子上,过程中要求大圆盘不能在小圆盘之上
思路
实际上我们可以把问题简化成最基本的两种情况:
①若只有一个块需要移动,那么只需要将其从a移动到c即可
②若有两个块需要移动,那么需要先将最上面的块移动到b,用b作为过渡存放最上面的块,
然后将最下面的块移动到c并将b的块也移动至c即可
然后无论是之后需要移动多少个块,我们都可以将其简化为上述两种基本类型
使用递归的方法,对移动个数每次减一,不断开辟新的栈,直到将其简化为基本类型
完成基本类型的计算后再不断的返回值到下一个栈即可实现目标
public class HanoiTower{
public static void main(String[] agrs){
Tower tower = new Tower();
tower.move(2, 'A', 'B', 'C');
}
}
class Tower{
//方法
//num 表示要移动的个数,a, b, c 分别表示A塔、B塔、C塔
public void move(int num, char a, char b, char c){
//只有一个盘的情况
if(num == 1){
System.out.println(a+"->"+c);
}else {
//若有多个盘,可以看成两个,即最下面的和上面的所有盘
//1.先移动上面所有的盘到b,借助c
move(num - 1, a, c, b);
//2.把最下面的这个盘移动到c
System.out.println(a+"->"+c);
//3.再把b塔的所有盘移动到c,借助a
move(num - 1, b, a, c);
}
}
}
注意点:我们只是给出移动的步骤,而无需考虑盘子本身
【Java复健指南03】递归思想的更多相关文章
- 【Java复健指南09】项目练习全解--房屋出租系统
一个基于文本界面的综合练习,主要用于串联和回忆知识点,比较简单 各个界面的设计样式 主菜单 =============房屋出租系统菜单============ 1 新 增 房 源 2 查 找 房 屋 ...
- 【Java复健指南15】链表LinkedList及其说明
链表LinkedList by Java 之前有写过一些记录(引用),但是忘了乱了,现在重新梳理一遍 链表是Java中List接口的一种实现 定义(引用) 链表(linked list)是一种物理存储 ...
- 《编程简介(Java) ·10.3递归思想》
<编程简介(Java) ·10.3递归思想> 10.3.1 递归的概念 以两种方式的人:男人和女人:算法是两种:递归迭代/通知: 递归方法用自己的较简单的情形定义自己. 在数学和计算机科学 ...
- Java工程师学习指南 入门篇
Java工程师学习指南 入门篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都 ...
- Java工程师学习指南 完结篇
Java工程师学习指南 完结篇 先声明一点,文章里面不会详细到每一步怎么操作,只会提供大致的思路和方向,给大家以启发,如果真的要一步一步指导操作的话,那至少需要一本书的厚度啦. 因为笔者还只是一名在校 ...
- Java工程师学习指南 中级篇
Java工程师学习指南 中级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我写的文章都是站 ...
- Java工程师学习指南 初级篇
Java工程师学习指南 初级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都 ...
- [剑指Offer]48-最长不含重复字符的子字符串(递归思想,循环实现)
题意 如题,字符串只含a-z,输出该子串长度.例:"arabcacfr",输出4. 解题思路 递归思想 计f(i)为以第i个字符结尾的最长不含重复字符的子串长度. 状态转移:计d为 ...
- 【系列】Java多线程初学者指南(1):线程简介
原文地址:http://www.blogjava.net/nokiaguy/archive/2009/nokiaguy/archive/2009/03/archive/2009/03/19/26075 ...
- Java工程师学习指南(入门篇)
Java工程师学习指南 入门篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都 ...
随机推荐
- [转帖]【k8s】5、资源管理命令-声明式
文章目录 一. yaml和json介绍 1.yuml语言介绍 2.k8s支持的文件格式 3.yaml和json的主要区别 二.声明式对象管理 1.命令式对象配置 2.声明式对象配置 3.声明式对象管理 ...
- vim 复制代码的方法
之前vim 复制代码 总是格式变错乱了 尤其是yaml文件 有的还带注释 非常痛苦 今天早上查了下 原来处理的方式非常简单 增加一个参数就可以了 方法为 1. vim 打开一个文件 2.输入 :se ...
- Oracle DBCA 静默删除以及建库的脚本
No.1 背景 公司最近有一个测试环境需要重新备份恢复 但是里面有6个数据库实例 400多G的数据文件. 一般情况下 需要drop user xxx cascade ; 然后执行 drop table ...
- 责任链和策略设计模式-基于Java编程语言
作者:京东物流 钟磊 1 前言 最近在梳理接口逻辑的时候发现,代码中使用的策略和责任链设计模式给我留下了非常深刻的印象.一个业务逻辑流程通常非常适合使用责任链和策略设计模式来实现,因为一个业务需求通常 ...
- 跟着文档学Fabric:获取通道配置
原文在这里. 1. 获取通道配置 peer channel fetch config config_block.pb -o $ORDERER_CONTAINER -c $CH_NAME --tls - ...
- GitHubDesktop汉化和下载
GitHubDesktop下载 这玩意官网下载速度特别慢 如果不想等待的可以戳下面链接进行下载 会实时同步更新的 下载地址:GitHubDesktop下载
- Pytorch分布式训练,其他GPU进程占用GPU0的原因
问题 最近跑师兄21年的论文代码,代码里使用了Pytorch分布式训练,在单机8卡的情况下,运行代码,出现如下问题. 也就是说GPU(1..7)上的进程占用了GPU0,这导致GPU0占的显存太多,以至 ...
- tensorflow语法【zip、tf.tile、tf.truncated_normal、tf.data.Dataset.from_tensor_slices、dataset中shuffle()】
相关文章: [一]tensorflow安装.常用python镜像源.tensorflow 深度学习强化学习教学 [二]tensorflow调试报错.tensorflow 深度学习强化学习教学 [三]t ...
- C/C++ Qt 编译打包项目
Qt程序编译后,需要去qt目录拷贝几个文件,与qt程序放在一起该程序才可以脱离开发环境而独立运行下去,在开发环境下编译好代码以后,还需要进行以下操作将其打包才可以在别的机器上正常运行. QT的下载地址 ...
- .NET Avalonia开源、免费的桌面UI库 - SukiUI
前言 今天分享一款.NET Avalonia基于MIT License协议开源.免费的桌面UI库:SukiUI. Avalonia介绍 Avalonia是一个强大的框架,使开发人员能够使用.NET创建 ...