每日算法(三十六)-java递归
递归(recursion):程序调用自身的编程技巧。
递归满足2个条件:
1)有反复执行的过程(调用自身)
2)有跳出反复执行过程的条件(递归出口)
递归与栈的关系
下面演示的是求n的阶乘
int Factorial(int n){
if (n == 0) return 1;
return n * Factorial(n - 1);
}
常常听到 “递归的过程就是出入栈的过程”,这句话怎么理解?我们以上述代码为例,取 n=3,则过程如下:
第 1~4 步,都是入栈过程,Factorial(3)调用了Factorial(2),Factorial(2)又接着调用Factorial(1),直到Factorial(0);
第 5 步,因 0 是递归结束条件,故不再入栈,此时栈高度为 4,即为我们平时所说的递归深度;
第 6~9 步,Factorial(0)做完,出栈,而Factorial(0)做完意味着Factorial(1)也做完,同样进行出栈,重复下去,直到所有的都出栈完毕,递归结束。
每一个递归程序都可以把它改写为非递归版本。我们只需利用栈,通过入栈和出栈两个操作就可以模拟递归的过程,二叉树的遍历无疑是这方面的代表。
但是并不是每个递归程序都是那么容易被改写为非递归的。某些递归程序比较复杂,其入栈和出栈非常繁琐,给编码带来了很大难度,而且易读性极差,所以条件允许的情况下,推荐使用递归。
练习
有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少对?
这里我们可以先把情况列举出来查看规律,
第一个月 1
第二个月 1
第三个月 2
第四个月 3
第五个月 5
第六个月 8
不难发现从第三个月开始数量是前两个月的和,与上面的斐波那契数列非常像,代码如下
public static int add(int month){
if(month==1|month==2){
return 1 ;
}else{
return add(month-1)+add(month-2);
}
}
非递归代码:
public static void addTwo(){
int s1=1;
int s2=1;
for(int month=1;month<13;month++){
if(month==1|month==2){
System.out.println("第"+month+"月数量为:"+s2);
continue;
}else{
int temp=s2;
s2=s1+s2;
s1=temp;
System.out.println("第"+month+"月数量为:"+s2);
}
}
}
练习二:十进制转二进制
递归代码
static String str="";
public static int binary(int data) {
if(data%2!=0)
{
str="1"+str;
}else {
str="0"+str;
}
if (data/2==0) {
return 1;
}
return 1+binary(data/2);
}
非递归:
public static void transForm(int data){
String str="";
while(data!=0){ //
str=data%2+str; //余数
data=data/2;
}
System.out.println(str);
}