1.递归的概述
递归:方法自己调用自己
递归的分类:
1.直接递归
public void a(){
a();
}
2.间接递归
public void a(){
b();
}
public void b(){
a();
}
递归的注意事项:
- 递归必须有结束的条件,保证递归可以停止下来,否则会抛出内存溢出的错误
- 递归有结束的条件,但是递归的次数也不能太多,否则会抛出内存溢出的错误
- 构造方法禁止递归
什么时候使用递归:
当我们频繁的调用一个方法,方法的主体不变,每次调用方法的参数改变,就可以使用递归
public class Demo01Recursion {
public static void main(String[] args) {
//a();
b(1);
}
/*
3.构造方法禁止递归
构造方法是创建对象使用的,递归调用自己,会在内存中一直创建对象,停不下来
*/
public Demo01Recursion() {
//Demo01Recursion();
}
/*
2.递归有结束的条件,但是递归的次数也不能太多,否则会抛出内存溢出的错误
11418,11406 内存使用频率是随时变化的,得到的结果不一样
Exception in thread "main" java.lang.*Error
*/
private static void b(int i) {//i=1,2,3,4...
System.out.println(i);
if(i==20000){
return;//结束方法,不在继续调用了
}
b(++i);
}
/*
1.递归必须有结束的条件,保证递归可以停止下来,否则会抛出内存溢出的错误
Exception in thread "main" java.lang.*Error
*/
private static void a() {
System.out.println("a方法!");
a();
}
}
2.练习:使用递归计算1-n的和
/*
练习:使用递归计算1-n的和
递归就是方法自己调用自己,只要我们使用递归,就需要定义一个方法,自己调用自己求和
*/
public class Demo02Recursion {
public static void main(String[] args) {
int s = sum(20000);
System.out.println(s);
}
/*
定义一个计算1-n和的方法
1-n的和就是n-1的和
n+(n-1)+(n-2)+(n-3)+...+1
已知:
n:10,100,1000,...
加到1结束
未知:
n-1
递归的目的:获取下一个被加的数字n-1
递归结束的条件:获取n-1==1的时候,结束递归
*/
public static int sum(int n){
//递归结束的条件:获取n-1==1的时候,结束递归
if(n==1){
return 1;
}
//递归的目的:获取下一个被加的数字n-1
return n + sum(n-1);
}
}
3.练习:递归求阶乘
package com.itheima.demo02Recursion;
/*
练习:递归求阶乘(重点)
n的阶乘: n!=n*(n-1)*(n-2)*...*1;
5!= 5*4*3*2*1;
*/
public class Demo03Recursion {
public static void main(String[] args) {
int i = jieCheng(5);
System.out.println(i);
}
/*
定义一个计算阶乘的方法
已知:
n:5,6,7,8,9...
乘到1结束
未知:
n-1
递归的目的:获取下一个被乘的数字n-1
递归的结束条件:获取n-1==1的时候结束
*/
public static int jieCheng(int n){//5,4,3,2,1
//递归的结束条件:获取n-1==1的时候结束
if(n==1){
return 1;
}
//递归的目的:获取下一个被乘的数字n-1
return n*jieCheng(n-1);
}
}
4.练习:使用递归遍历文件夹和文件夹中的子文件夹
package com.itheima.demo02Recursion;
import java.io.File;
/*
练习:使用递归遍历文件夹和文件夹中的子文件夹(遍历多级文件夹)
遍历d:\\aaa目录
d:\\aaa
d:\\aaa\\aaa.java
d:\\aaa\\aaa.txt
d:\\aaa\\全球通史.txt
d:\\aaa\\a
d:\\aaa\\a\\a.java
d:\\aaa\\a\\a.jpg
d:\\aaa\\b
d:\\aaa\\b\\b.avi
d:\\aaa\\b\\B.JAVA
*/
public class Demo04Recursion {
public static void main(String[] args) {
File file = new File("d:\\aaa");
getAllFile(file);
}
/*
定义一个方法,参数传递要遍历的文件夹File对象
在方法内部对文件夹进行遍历
*/
public static void getAllFile(File dir){
System.out.println(dir);//打印要遍历的文件夹名称
File[] files = dir.listFiles();
for (File f : files) {
//判断遍历得到的文件对象f,是否是一个文件夹
if(f.isDirectory()){
//f是一个文件夹,继续遍历这个文件夹
//我们发现getAllFile方法,就是一个传递文件夹,遍历文件夹的方法
//调用getAllFile方法即可,传递要遍历的文件夹(f==a|f==b)
getAllFile(f);//方法中自己调用自己==>递归
}else{
//f就是一个文件,打印==>f.toString()方法
System.out.println(f);
}
}
}
}
5.练习:文件搜索
package com.itheima.demo02Recursion;
import java.io.File;
/*
练习:文件搜索
遍历d:\\aaa目录,只打印以.java(.JAVA)结尾的文件,不分区大小写
d:\\aaa
d:\\aaa\\aaa.java
d:\\aaa\\aaa.txt
d:\\aaa\\全球通史.txt
d:\\aaa\\a
d:\\aaa\\a\\a.java
d:\\aaa\\a\\a.jpg
d:\\aaa\\b
d:\\aaa\\b\\b.avi
d:\\aaa\\b\\B.JAVA
*/
public class Demo05Recursion {
public static void main(String[] args) {
File file = new File("d:\\aaa");
getAllFile(file);
}
/*
定义一个方法,参数传递要遍历的文件夹File对象
在方法内部对文件夹进行遍历
*/
public static void getAllFile(File dir){
File[] files = dir.listFiles();
for (File f : files) {
//判断遍历得到的文件对象f,是否是一个文件夹
if(f.isDirectory()){
//f是一个文件夹,继续遍历这个文件夹
getAllFile(f);//方法中自己调用自己==>递归
}else{
/*
f就是一个文件,打印==>f.toString()方法
需求:只打印以.java(.JAVA)结尾的文件,不分区大小写
解决:
判断f是不是一个以.java(.JAVA)结尾的文件,是则打印
实现步骤:
1.把f对象(File对象)转换为String
a==>f.toString() "d:\\aaa\\aaa.java"
b==>f.getPath() "d:\\aaa\\aaa.java"
c==>f.getName() "aaa.java"
2.使用String类的方法endsWith判断字符串是否以.java结尾
3.是.java结尾的文件则打印
*/
/*String name = f.getName();
name = name.toLowerCase();
boolean b = name.endsWith(".java");
if(b){
System.out.println(f);
}*/
if(f.getName().toLowerCase().endsWith(".java")){
System.out.println(f);
}
}
}
}
}