专栏首页农历七月廿一深入浅出的理解一下JAVA的递归思想

深入浅出的理解一下JAVA的递归思想

写在前面

我呢一直写的是js相关的文章,以至于很多人认为我是一个标准的前端工程师,这也不奇怪,后端的谁会瞎搞js呢?其实呢我是一个地地道道的写java的菜逼,嗯,菜逼,只是公司的要求被迫我写了js,可能是看我java太差了,或者是我长的比较适合写js等等吧,总之导致的结果是我写了很长一段时间的js,今天呢js写的也不少了,所以今天我想写一篇关于java的文章,看看我是不是还和以前一样的菜逼,其实写了那么久的js给我感觉是和java真的很多地方是一样的,两种语言虽然说是不同的,但是其实仔细的体会一下,也没什么特别不同的地方,这里说多说一点,很明显的一个区别可能就是java是强类型语言,js是弱类型语言,但是java是面向对象编程的, js其实也是的,所谓的强类型语言就是说呢他不同的变量必须使用不同的类型来声明,不能像js一样所有的都是var或者是let,当然还有很多大大小小的区别,这里我就不献丑了,毕竟看我的文章的可能还有java的大神,我就不班门弄斧了,今天要说的是java的递归的思想,为什么要说这个呢?其实很简单,就是觉得这个是java一个很有意思的地方,今天我们就看看有意思的在哪里!

首先我们要明白什么是递归思想:

我们都知道,java里面的每一个功能都会被封装成一个方法,第一是为了装逼,第二呢是为了更好的维护,方法的原则是每一个功能封装成一个方法,这也是java原子性的体现,那么到这里我们就会想啊,既然方法写出来了,那么一定是需要别的方法调用的是不是,不然单写一个没有被调用过得方法没有什么意义是不是,就好像你写一个带有参数的方法,形参写好了,但是没有人调用,也就是没有实参传进来,那么这个方法我们认为是没有意义的方法,所以写了方法就一定要被调用的才是有意义的,那么既然是被调用,就要思考一个问题,被谁调用?

这里我们写一个例子:

package com.gaojizu.studybymyself;
/**
 * 测试递归的思想
 *@author clearlove
 */

public class Test_Recursion {
	
	public static void test01() {
	    test02();
		System.out.println("test01");
		
	}
	public static void test02() {
		System.out.println("test02");
	}
	
	public static void main(String[] args) {
	    test01();
		
	}

}

ok这里我们可以看到我写了两个方法,test01和test02,那么这里我们会想这个很简单的啊,函数从mian进入,执行01

的时候将执行02的方法:

没有问题,那么我们难道不想一下为什么我们不可以01里面直接调用01呢?自己调用自己会有什么后果呢?

我们可以试一下:

package com.gaojizu.studybymyself;
/**
 * 测试递归的思想
 *@author clearlove
 */

public class Test_Recursion {
	
	public static void test01() {
	    test01();
		System.out.println("test01");
		
	}
	public static void test02() {
		System.out.println("test02");
	}
	
	public static void main(String[] args) {
	    test01();
		
	}

}

这个时候我们看一下:

ok这里会报错,什么意思呢?很简单内存溢出了,为什么呢?这里其实就是递归的一个简单的雏形思想,自己调用自己,为什么是雏形呢?因为出错了啊,不完美啊,为什么会出错呢?接着往下看,既然出错了我们就要先搞明白哪里出的问题,我们绘图模拟一下他的代码执行的过程:

没有画之前我们先debug一下,看看这个代码怎么执行的:

这里我们会发现一个问题,就是代码走到test01的时候啊不走了,为什么不走了呢?代码什么情况下会不走?第一代码执行结束,第二代码不知道怎么结束!这个显然就是不知道怎么结束了!

我们画一下:

这里就很有意思了,代码走到这里01的时候他发现下面要执行的是test01,也就是自己,所以就直接回到方法头部开始重新执行,第二次还是自己,所以就陷入一个无限循环中,这里可能你们一看就明白,但是很少有人去思考这里的问题,这个情况会导致在我们计算机中有限的内存出现无限的数据,所以导致了内存溢出!可能很多人就说了,这不是和C语言中的Goto方法差不多嘛!虽然java中的goto已经不让用了,但是思想其实是差不多的,虽然不让用了但是我们还是可以在java中找到他的影子的,例如下面的代码:

/*
 * 
 * author : clearlove
 * 测试一下c语言中的goto的思想用法
 * 写一个101到150之间的质数
 */
package studybymyself;

public class Test_continue {
	public static void main(String[] args) {
		int count = 0;
		outer : for(int i = 101;i<150;i++) {
			for(int j =2;j<i / 2;j++) {
				if(i%j==0) {
					continue outer;
				}
			}
			System.out.print(i+" ");
		}
	}
}

这里就是goto的影子的用法,其实是和我们递归的思想是很像的,ok说多了,我们接着说这递归的问题!那么既然找到问题的所在就要像怎么解决呢?想解决很简单,既然是他因为没有找到怎么结束我们告诉他怎么结束不就行了吗?是不是,所以我们其实可以直接给他加一个判断,告诉他,什么时候结束!

package com.gaojizu.studybymyself;
/**
 * 测试递归的思想
 *@author clearlove
 */

public class Test_Recursion {
	
	public static void test01() {
	   a++;
		System.out.println("test01"+a);
		if(a <= 10) {
			test01();
		}
		
	}
	public static void test02() {
		System.out.println("test02");
	}
	
	public static void main(String[] args) {
	    test01();
		
	}

}

我们告诉他,只要a的值大于10了,那么就停止!这样不就可以了吗?当然是可以的。

ok总结一下:怎么写一个完整的递归呢?它包含两部分,第一是递归头,第二是递归体

递归头就是什么时候不调自己的方法,如果没有就和之前的一样,陷入一个死循环

递归体就是什么时候调用自己的方法,如果没有就将毫无意义!

下面我们写一个比较经典的例子:阶乘

所谓的阶乘我们要明白是怎么回事!就是说8的阶乘就是8*(8-1)*(8-2)...(1)

我们看一下规律:这里的变量只有比他本身数值依次小一的数,那么其实用while或者for循环都是很简单的一个题目,这里我们用递归的思想写一个:

/**
 * 
 *测试递归   自己调用自己就是递归的思想
 *@author clearlove
 */
package com.gaojizu.studybymyself;

public class Test_Recursion {
	/**
	 * 
	 * @param n是形参的数值
	 * @return 阶乘的结果值
	 */
	public static long fact(int n) {
		if(n==1) {
			return 1;
		}else {
			return n*fact(n-1);
		}
	}
	public static void main(String[] args) {
		
		long sum = fact(5);
		System.out.println(sum);
	}

}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java继承特性以及重写现象的内存分析

    今天我们说一下Java面向对象中的一个特性-继承,然后做一下他的内存分析,理解一下重新现象的情况。

    何处锦绣不灰堆
  • 破解虚拟机软件-安装个Linux玩玩

    之前写安装windows的时候,原本是准备用虚拟机模拟一下具体的过程的,但是因为自己手贱,卸载了虚拟机,所以没有机会做教程,现在需要写虚拟机的使用的时候了,哎,...

    何处锦绣不灰堆
  • 快速创建一个SpringBoot项目

    作为一个喜欢研究各种奇葩前端技术的我,最近火的不行的SpringBoot不去看一下确实是说不过去,虽然是后端的框架,但是希望可以从中得到一些启发,有利于自己的前...

    何处锦绣不灰堆
  • java&quot;小心机&quot;(1)【资源彩蛋!】

    方法名和参数列表(它们合起来被称为“方法签名”)唯一地标识出某个方法。(引用自[Thinking in java])

    KEN DO EVERTHING
  • PHP面向对象程序设计中的self、static、parent关键字用法分析

    本文实例讲述了PHP面向对象程序设计中的self、static、parent关键字用法.分享给大家供大家参考,具体如下:

    砸漏
  • laravel实现简单用户权限的示例代码

    最近用laravel设计后台,后台需要有个权限管理。权限管理实质上分为两个部分,首先是认证,然后是权限。认证部分非常好做,就是管理员登录,记录session。这...

    砸漏
  • ASP.NET Core 使用 Alipay.AopSdk.Core 常见问题解答

    晓晨
  • 重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」

    编程开发这条路上的知识是无穷无尽的,就像以前你敢说精通Java,到后来学到越来越多只想写了解Java,过了几年现在可能想说懂一点点Java。当视野和格局的扩大,...

    小傅哥
  • PHP中抽象类,接口功能、定义方法示例

    本文实例讲述了PHP中抽象类,接口功能、定义方法。分享给大家供大家参考,具体如下:

    砸漏
  • 自适应的逗号

    TalkPython

扫码关注云+社区

领取腾讯云代金券