一:递归和循环
递归:程序调用自身的编程技巧称为递归。
循环:for语句或者for each语句实现。
递归是我们初学程序常常接触的小问题。麻雀虽小,可是深入理解它还是大有学问。
比如,请用程序计算 n!。首先我们应该先要知道 n!是什么;如 5!=5 * 4 * 3 * 2 * 1,3!= 3 * 2 * 1等等。按照上面的思路,n!= n * (n-1) * (n-2) * (n-3) * (n-4) *.....* 3 * 2 * 1;我们最直白的思想是非递归运用for循环进行阶乘进行求解。
import java.util.Scanner;
public class Resursion01 {
public static void main(String[] args) {
System.out.println("请输入您想阶乘的数:");
Scanner sc1 = new Scanner(System.in);
int n = sc1.nextInt();
if(n < 0){
System.out.println("对不起您输入的数不合法!");
return;
}
int sum = 1;
for(int i = n; i > 0; i--){
sum *= i;
}
System.out.println(n+"! = "+sum);
}
}
上面的程序时间复杂度为O(n);空间复杂度比较小。(注:因为sum定义为int型,故进行阶乘的数不要太大,容易溢出)
本节程序讲的是递归,我们当然要用递归去解决一下这个问题。递归就是自己调用自己,但是有判断条件,并且当判断量大于终止条件就一直向下递归,当不满足终止条件时,它就向上递归返回值。最终给出我们想要的结果。故运用递归进行阶乘的代码为:
import java.util.Scanner;
public class Resursion02 {
public static void main(String[] args) {
System.out.println("请输入向进行阶乘的数N:");
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
if(n < 0){
System.out.println("输入的N不合法.");
return ;
}
int sum = f(n);
System.out.println(sum);
}
public static int f(int n){
if(n == 1){
return 1;
}else{
return n * f(n-1);
}
}
}
这个程序的空间复杂度和时间复杂度都很大,所以我们在运用递归时一定要注意。(注:因为sum定义为int型,故进行阶乘的数不要太大,容易溢出)
n!的阶乘程序递归图为:
二:递归和循环分析
递归的优劣:
递归的优势:递归的程序代码简单易读,在实现某些算法时还是有特定的优势:比如用递归实现数据结构中的Tree遍历前序遍历(先遍历根节点,再遍历左子树,最后遍历右子树)、中序遍历(先遍历左子树,再遍历根节点,最后遍历右子树)、后续遍历(先遍历左子树,再遍历右子树,最后遍历根节点);
递归的劣势:递归是程序本身调用自身,函数调用自身是有时间和空间消耗的(栈空间的消耗),在递归每一次调用自身这个函数时,都需要在内存中分配一定的空间以保存参数、临时变量以及返回地址等信息,而在栈中数据的出栈和入栈都是有时间需求的,故运用递归时会大大降低程序的运行效率,尤其是当递归基数比较大时,效率尤为明显,故在一般的开发中不会运用递归。
循环的优劣:优势,重复执行一些步骤,执行完的就释放空间,一直到一个终止条件,故循环的空间复杂度比较低一些。