递归相信很多人都用过,但所有人都知道递归的秘密吗?
这里我分2中情况理解下递归。
先看段代码:
例1:
private static void calc(int num) {
System.out.println("num:" + num);
num--;
if (num < 2) {
return;
}
calc(num);
System.out.println("num after calc:" + num);
}
输出:
num:5
num:4
num:3
num:2
num after calc:2
num after calc:3
num after calc:4
输出是先递减,然后递增。初次接触,可能会惊讶下,然鹅,对于细心的人,断点调试过的,或许已经发现了这个原理。但是不是又不好解释?没关系,这里第一个例子我先把现象放在这里。
例2:
private static boolean calc1(int num) {
if (num < 2) {
return false; // 返回给递归的 注释1
}
System.out.println("num:" + num);
num--;
if (calc1(num)) {
System.out.println("num after calc:" + num);
}
return true; // 函数返回 注释2
}
还是这个例子,第一个没有返回值,大家没注意return的问题,一般情况,return就直接返回了整个方法,但在递归里,发现注释1中返回的是递归调用处,注释2返回的,才是整个函数。整个可以调用下试试。
boolean calc1 = calc1(5);
System.out.println("calc1 is return: " + calc1);
calc1 is return: true
第一眼看到的,真正终止递归的,是num < 2,那应该是return false 才对吧?为什么是true呢?就是了,因为注释1处的return,是return给if(calc1(num))这里的,是告诉递归者,不能再递归了,你要停止。然后后面的就你就好理解了吧。最终是return true。
大家一般使用,都是递归的处理下问题,遇到某种情况就退出,处理的理解不会有这样的诡异和深刻。好了。这里是一部分人对递归没有理解到的地方。那递归出这样的东西出来,那递归的真正的原理是啥呢?
细心的人观察出来了,
num:5
num:4
num:3
num:2
num after calc:2
num after calc:3
num after calc:4
这个输出,不是先进后出么?
大概就是这样的,那这个不就是栈吗?对,就是栈。你可以认为递归,就是把需要递归的代码快放在一个栈中,放进栈中的代码,会依次执行,谁先进,谁就先执行了,然后就是等待递归结束,再从栈中弹出来,执行递归之后该执行的动作。编译器,不可能在一块代码中,肆无忌惮的递归执行的,只有是搞出另一个方法快出来,然后互相调用,跳转。到这里,大家对递归是不是有一个深刻的认识了?
见过递归的溢出么?
Exception in thread "main" java.lang.StackOverflowError
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.PrintStream.write(PrintStream.java:482)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
at java.io.PrintStream.write(PrintStream.java:527)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:806)
你看看,一个死循环的递归,系统就会告诉你,栈溢出了。
至此,递归的一些小秘密。
递归如此特性,那有没有和他完美其他的东西呢?
嗯嗯,下次我整理出完美利用递归特性的东西:归并排序算法。
看懂这个先,然后再去看归并排序算法。