递归,即程序(函数)直接或者间接调用自己的一个过程。
递归算法主要有四个特点:
1. 必须有可达到的终止条件,不然程序(函数)将陷入死循环(死锁);
2. 子过程可通过再次递归的方式调用求解或因满足终止条件而直接求解;
3. 子过程的规模比原过程小(一般是折半),或更接近终止条件;
4. 所有子过程的解构成整个过程的解的集合。
先来一段代码:
下面是分组归并排序(分治法)的递归过程:
在Java环境下运行:
void Mergesort(int arr[],int s,int t) {
int m,r1[]=new int [100]; //假设最多存放100个元素
if (s==t) {
return;
} //必须写上'return',不然进入死循环
else{
m = (s + t) / 2;
Mergesort(arr, s, m); //左边有序
/*Mergesort(arr, m + 1, t); //右边有序 Merge(arr, r1, s, m, t); //再将两个有序数列合并 for(int i=s;i<=t;i++){ arr[i]=r1[i]; System.out.print(arr[i]+" "); }*/
System.out.print(m);
}
System.out.println();
}
在Main输入:int arr[]={7,6,3,4,5,2,1} ; Mergesort(arr,0,7);
Console显示:0
1
3
分析:
首先简化过程,将无关语句删减,冗余语句则用”…”进行省略,方便阅读。
主过程Mergesort开始运行,判断if条件不符合后转入else语句方向,执行语句。
当遇到同名函数时,后面的语句暂不执行,放入内存栈中保留,之后,从头开始运行。
–>需要注意的是,这里所说的“从头开始”是相对的,调用自身后所含参数是变动的,而新过程的语句和主过程(原过程)完全一致,继续从上到下重新执行,便有“从头开始”一说。<–
第二次以后的执行过程跟第一次同理,运行后先判断条件,后选择if-else的执行方向。如再次遇到同名函数,则继续调用自身。如此反复执行,直到递归结束为止,这就是所谓的“递归”。
为了方便分析,我们把主过程称为原过程,用M1表示;调用自身后执行的过程称为子过程,以 Mi ( i=2,3,…,n)表示。
要搞清递归过程,判断其入口和出口显得即为关键,而递归的终止点,是一个无参值标记,一般为空值。
找出入口、出口和终止点后,不难发现,原来递归是这么一个过程:
void Mergesort(int arr[],int s,int t){ // M1 Starts
int m,r1[]=new int [100]; // 假设最多存放100个元素
if (s==t) {
return;
} // 必须写上'return',不然进入死循环
else{
m = (s + t) / 2;
Mergesort(arr, s, m){ // M2 Starts
... //省略(后面同)
if ... //不执行
else{
m = (s + t) / 2;
Mergesort(arr, s, m){ // M3 Starts
...
if ... //不执行
else{
m = (s + t) / 2;
Mergesort(arr, s, m){ // M4 Starts
...
if (s==t) {
return; } //递归终止
else...
... //不执行
System.out.println();
} // M4 Ends
System.out.print(m); // E3 Prints m3
}
System.out.println(); // I3
} // M3 Ends
System.out.print(m); // E2 Prints m2
}
System.out.println(); // I2
} // M2 Ends
System.out.print(m); // E1 Prints m1
}
System.out.println(); // I1
} // M1 Ends
小结:
1. 递归是调用自身的一种算法,或是一种过程;
2. 多次递归组合而成的整过程更像是一种嵌套了多个自元素(同名函数)的一体化函数;
3. 递归执行的语句在遇到同名函数前正常执行,而其后的语句则暂时保留在内存中,待其递归后得到的
子过程完全结束后才继续执行。故有规律:越是最前的函数语句,递归后越在最后执行。4. 找出每次递归过程的入口、出口以及整个递归过程的终止点极为关键;
5. 划分归并的思想在递归算法中得到了很好的运用,此思想在很多算法里都有极为精妙的体现。
如有问题,欢迎指正,谢谢!