前言

在数据结构算法设计中,或者一个方法的具体实现的时候,有一种方法叫做“递归”,这种方法在思想上并不是特别难,但是实现起来还是有一些需要注意的。虽然对于很多递归算法都可以由相应的循环迭代来代替,但是对于一些比较抽象复杂的算法不用递归很难理解与实现。

递归分为直接递归和间接递归,就简单分享一下两个小的直接递归。

对于递归的概念,其实你可以简单的理解为自己定义自己,记得小时候看过一部电视剧《狼毒花》,里面主角叫做“常发”,但是个文盲,老师问他叫什么,他说“常发”。“哪个常?”“常发的常啊!”“哪个发?”“常发的发啊!”结果第二节课老师就让一群小朋友一起喊“常发的常,常发的发,傻瓜的傻,傻瓜的瓜”。言归正传,显然在多数情况下递归是解释一个想法或者定义的一种合理方法。在思想上递归类似于数学中曾经学过的数学归纳法。

递归的实现:

递归的实现要注意有两点:一个递归的选项和一个非递归的选项,后者成为基础情形(base case)。基础情形是递归的终结情形,没有基础情形或者处理不好都会导致无穷递归,这是我们不想要的结果。递归实现起来最关键的是处理好基础情形。 结合具体事例在说一下递归回溯的过程。

下边来写两个小程序:

1、爬楼梯算法:已知一个楼梯有n个台阶,每次可以选择迈上一个或者两个台阶,求走完一共有多少种不同的走法。

方法如下:

递归函数有返回值的比没有返回值的麻烦一点,因为一个函数只有一个返回值,但是递归还要求有基础情形的存在,所以还必须有if判断来终止递归。所以在每一个if或者else后边都有一个return,这样保证函数在任何一种情况下都有且仅有一个返回值。

分析一下这个算法:

A:如果有0个台阶,那么有0种走法,这个不用多说;

B:如果有1个台阶,那么有1种走法;

C:如果有2个台阶,那么有2种走法(一次走1个,走两次;一次走两个);

以上的B和C就是基础情形。

D:接下来就是递归了,如果台阶数目多于2个,那么首先第一步就有两种选择:第一次走1个,或者第一次走两个。这样除了第一次后边的走法就有了两种情形:climbStairs(n-1)和climbStairs(n-2)。这样一直递归下去,直到出现到了基础情形(即n=1或n=2的情形),递归到这个地方(基础情形),然后开始回溯 ,这就是所说的和递归密切相关的“回溯”了。回溯,顾名思义就是从结果倒着回去,找到整个过程,进而分析这个路径或者说是实现的过程。

需要注意的是,这个算法实现思路上简单,但是复杂度并没有降低,还牵扯回溯保存堆栈问题(其实递归的设计尽量避免这种嵌套两个的递归方式(climb(n)中包含climb(n-1)和climb(n-2)),这种操作会使得堆栈开辟空间随着n的增大以指数型增长,最终程序很容易崩溃),而且在台阶数目多到一定数量的时候会越界(走法次数会超出int的范围),所以递归程序很大程度上就是思想实现设计上简单理解一些。

下边是源代码:

package leetcode;

public class ClimbStairs {

//**************************************************************

public int climbStairs(int n) {

int i=1;

if(n<=0)

return 0;

if(n==1){

return i;

}

if(n==2){

i++;

return i;

}

else

return climbStairs(n-1)+climbStairs(n-2);

}

//**************************************************************

public static void main(String []args){

ClimbStairs cs=new ClimbStairs();

int a =cs.climbStairs(4);

System.out.println(a);

}

}

然后还有几个比较典型的递归问题:比如说迷宫问题,或者最经典的汉诺塔问题,下边都给出源码,大家一块儿学习一下。

汉诺塔问题:一次只能移动一个盘子;不能把大盘子放在小盘子上;除去盘子在两个柱子之间移动的瞬间,盘子必须都在柱子上。(在这三点要求下把盘子从起始柱子A全部移动到目标柱子C上)

代码如下:

基础情形:n==1的时候终止递归,进行回溯。

public class HanNuoTower {

public void tower(int n,char s,char m,char e)//n个塔从s经过m最终全部移动到e

{

if(n==1)

move(s,e);

else

{

tower(n-1,s,e,m);

move(s,e);

tower(n-1,m,s,e);

}

}

public void move(char s,char e){

System.out.println("move "+s+" to "+e);

}

public static void main(String []args){

HanNuoTower hnt =new HanNuoTower();

hnt.tower(4,'A','B','C');

}

}

迷宫走法:二维数组构成一个迷宫,1表示通路,0表示不通,找到一条路径从起始点(traverse函数的参数)到终点(右下角点)。

基础情形:row=grid.length-1&&column=grid[0].length-1时done=true;

public class Maze {

private final int TRIED=3;

private final int PATH=7;

private int [][] grid={{1,1,1,0,0,1,0,1,0,0},

{0,0,1,1,1,0,0,0,0,0},

{1,0,1,0,0,0,1,1,1,1},

{1,1,1,1,1,0,0,0,1,1},

{0,0,0,0,1,1,1,0,0,0},

{1,0,1,0,1,0,0,1,0,0},

{1,0,0,1,1,1,1,1,1,1}};

public boolean traverse(int row,int column){

boolean done =false;

if(valid(row,column))

{

grid[row][column]=TRIED;

if(row==grid.length-1&&column==grid[0].length-1)

done=true;

else

{

done=traverse(row+1,column);//down

if(!done)

done=traverse(row,column+1);//right

if(!done)

done=traverse(row-1,column);//up

if(!done)

done=traverse(row,column-1);//left

}

if(done)

grid[row][column]=PATH;

}

return done;

}

private boolean valid(int row,int column){

boolean result=false;

if(row>=0&&row=0&&column

if(grid[row][column]==1)

result=true;

return result;

}

public String toString(){

String result="\n";

for (int row=0;row

for(int column=0;column

result +=grid[row][column]+" ";

}

result+="\n";

}

return result;

}

public static void main (String []args){

Maze maze=new Maze();

System.out.println(maze);

if(maze.traverse(0, 0))

System.out.println("The maze was successfully travelled!");

else

System.out.println("There is no possible path.");

System.out.println(maze);

}

}

还有一个九连环的操作,有兴趣的话可以一起看看。Java递归解决九连环问题

java递归算法经典实例_Java实现简单的递归操作方法实例相关推荐

  1. java古典兔子问题c语言,Java递归算法经典实例(经典兔子问题)

    Java递归算法经典实例(经典兔子问题) 题目:古典问题:3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 分析:首先我们要明白题目的意思 ...

  2. java技术详解_Java反射技术详解及实例解析

    前言 相信很多人都知道反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替 ...

  3. java 非静态 初始化_Java非静态代码块和实例初始化过程

    1 非静态代码块 非静态代码块特点 ①可以为实例变量(非静态的属性)初始化 ②每次创建对象的时候,都会执行一次,且先于构造器执行 ③若有多个非静态的代码块,那么按照定义的顺序从上到下依次执行 ④代码块 ...

  4. java邮件程序实例_java 发送邮件简单实例

    全部代码: EmailAuthenticator.java package com.gjw.test; import javax.mail.Authenticator; import javax.ma ...

  5. java猜拳游戏代码_Java实现简单猜拳游戏

    本文实例为大家分享了java实现简单猜拳游戏的具体代码,供大家参考,具体内容如下 看网上的猜拳游戏那么多,但都是用switch输入数字,所以用if嵌套,写一个简单的猜拳游戏 package game; ...

  6. java 异或 排序_Java的位运算符详解实例——与()、非(~)、或(|)、异或(^)...

    位运算符主要针对二进制,它包括了:"与"."非"."或"."异或".从表面上看似乎有点像逻辑运算符,但逻辑运算符是针对两 ...

  7. Java英汉翻译程序_java实现简单的英文文本单词翻译器功能示例

    本文实例讲述了java实现简单的英文文本单词翻译器功能.分享给大家供大家参考,具体如下: 直接上代码: package fanyi; import java.io.bufferedreader; im ...

  8. java绕过加密密码_Java实现简单密码加密功能

    本文实例为大家分享了Java实现简单密码加密案例,供大家参考,具体内容如下 需求: 首先将一组数据倒序,然后将每位数字都加上5,再用和除以10的余数代替该数字, 最后将第一位和最后一位数字交换. 请任 ...

  9. java socket编程心跳_Java Socket编程心跳包创建实例解析

    1.什么是心跳包? 心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包. 用来判断对方(设备,进程或其它网元)是否正常运行,采用 ...

最新文章

  1. ML-kNN 多标签k近邻算法 MLL Week 1
  2. AJAX 在Django 设置csrf_token
  3. linux 删除o开头的文件,linux实现除了某个文件或某个文件夹以外的全部删除
  4. 《Objective-C基础教程》第二章 对C的扩展
  5. WebStorm自定义主题/护眼主题
  6. js数组按中文拼音排序_这才是选择排序正确的打开方式!
  7. VSCode配置Python教程
  8. 关于连接数据库出现时差问题的解决方法
  9. 邮箱登录入口官网是哪个?域名邮箱登录入口展示
  10. SysML 第一讲:SysML简介
  11. uniapp唤醒手机地图app
  12. 迅雷因版权问题不能访问
  13. android 光线传感器的使用
  14. 项目中常用的Util方法
  15. 【叔小生】JavaScript进阶篇
  16. “被裁员后,我领悟到的8个残酷真相”
  17. Java之字符类型char
  18. VMware安装Ubuntu Kylin系统
  19. 华为正式开源方舟编译器,开源了,它真的开源了!
  20. 【DFS专题训练】踏青 C++程序题 连通块问题

热门文章

  1. tensorflow streaming_recall@kprecision@k与sklearn的区别
  2. 用C++打开指定网址
  3. HTML_hao123 1
  4. 告诉你怎样选择虚拟主机!
  5. micropython刷固件
  6. python elasticsearch bulk_Elasticsearch之批量操作bulk
  7. 白话数字签名(3)—Web程序中的数字签名
  8. MPU6050-DMP读不出数据
  9. The meaning of path integral formulation
  10. 强化学习系列7:无模型的蒙特卡洛法