黑马程序员_JavaSE基础知识总结四:递归与迭代

------ android培训java培训、期待与您交流! ----------


一、什么是递归?

递归算法:是一种直接或者间接地调用自身的算法,就我个人的理解而言,不论是直接还是间接,其算法的流程走向必须形成封闭(即本身属于广义上的循环过程),否则递归将不能形成。在计算机编写程序中,递归算法对解决很多类问题是十分有效,它使算法的描述简洁而且易于理解。

 

二、递归算法的特点:

递归过程一般通过函数或子过程来实现。

递归算法:在函数或子过程的内部,直接或者间接地调用自己的算法。

递归算法的实质:是把问题转化为规模缩小了的同类问题的子问题。然后递归调用函数(或过程)来表示问题的解。

 

递归算法解决问题的特点:

(1)递归就是在过程或函数里调用自身。

(2)在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。

(3)递归算法解题通常显得很简洁,但递归算法解题的运行效率较低,即占用内存很大,有时这种情况用栈来代替解决。所以一般不提倡用递归算法设计程序

(4)在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。

 

递归算法所体现的“重复”一般有三个要求:

一是每次调用在规模上都有所缩小(通常是减半);

二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);

三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

最后我再补充一点:递归只是用在简单的循环场合中,这种场合就是递归函数体只含有一个IF-ELSE语言的情况:

权限修饰符+(static)+函数返回类型+函数名(参数列表){

if(递归结束条件){递归结束终值赋值语句;return 返回值;}

else{累计计算+循环调用函数语句;

     return 返回值;}

}

其余的复杂循环(甚至嵌套)情况建议不用递归,因为递归过程中所用到的变量都在递归结束前的过程中一直占用着内存,如果循环过程又趋于复杂则内存耗用量将显著提升,运行速度也将下降.


二、一些范例

1、完成1 ~ 100的累加操作 —— 最早的做法,使用while完成


<span style="font-size:18px;color:#333333;">public class Hello {
	public static void main(String args[]){
		int sum = 0 ;
		int x = 1 ;
		while(x<=100){
			sum += x ;
			x++ ;
		}
		System.out.println(sum) ;
	}
}</span>

这种代码之中结束条件是:x>100,那么现在将程序换到递归完成。


<span style="font-size:18px;color:#333333;">public class Hello {
	public static void main(String args[]){
		System.out.println(fun(100)) ;
	}
	public static int fun(int num){
		if (num == 1) {
			return 1 ;
		}
		return num + fun(num - 1) ;
	}
}</span>

这个时候的fun()方法的调用就相当于:fun(100) + fun(99) + fun(98) +  + fun(1) ;

可是,递归本身操作的时候会存在内存的溢出问题,所以开发中使用并不多见,除非万不得已的时候。

25个人坐在一起问第5个人多少岁答,比第4个人大2岁。 第4个人说他比第3个人大23个人比第2个人大22个人比第1个人大2岁,问第1个人时回答是10岁。第5个人到底多大?

直接通过递归调用完成。


<span style="font-size:18px;color:#333333;">public class Hello {
	public static void main(String args[]){
		System.out.println(age(5)) ;
	}
	public static int age(int count){
		if(count == 1){
			return 10 ;
		}
		return 2 + age(count - 1) ;
	}
}</span>

3编写一个方法,此方法可以将一个整数变为二进制输出。

二进制的求法:数字除以2取模,等数字计算到0了,也就不取了,现在根本就不知道要除以多少次,那么就要改变做法,继续使用递归完成。

<span style="font-size:18px;color:#333333;">public class Hello {
	public static void main(String args[]){
		binary(2389) ;
	}
	public static void binary(int num){
		if(num / 2 != 0){
			binary(num / 2) ;	// 改变递归的条件
              System.out.print(num % 2) ;
		}
	}
}</span>

4、求斐波那契数列第n项,n<30,斐波那契数列前10项为 1,1,2,3,5,8,13,21,34,55

<span style="font-size:18px;color:#333333;">public class Test2 {
	public static void main(String[] args){
		
		//人机交互,让用户自己输入数字n
		System.out.println("请输入您要求的斐波拉契数列第n(n<30)项");
		System.out.println("n=");
		
		//创建Scanner对象,接收用户输入数据;
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		
		//判断数字n是否非法
		if(n >= 1 && n < 30){
			System.out.println("该数列第" + n + "项为:" + fibonacciMethod(n));
		}else {
			System.out.println("输入非法,请重新运行程序并输入一个(1,30)之间的整数");
			return;
		}
		
			
		}
	//解法一:递归调用。递归算法简洁,易于描述和理解,但解题的运行效率较低,即占用内存很大,有时这种情况用栈来代替解决。所以一般不提倡用递归算法设计程序。
	/*public static long fibonacciMethod(int n){
		if(n == 1 || n == 2){
			return 1L;
		}else {
			return fibonacciMethod(n-1) + fibonacciMethod(n-2);
		}
		
	}*/
	
	
	//解法二:常规解法,利用for循环进行迭代
	//不确定这个返回值是多大,因此用long来接收
	public static long fibonacciMethod(int n){
		
		//如果n==1或2,直接返回1
		if(n == 1 || n == 2){
			return 1L;
		}
		
		//定义f1,f2,f为下面迭代做准备;
			long f1 = 1L;
			long f2 = 1L;
			long f = 0;
			
			//注意:i<n-2,因为前两个数在上面已经定义过了
		for(int i = 0; i < n-2; i++){
			//令f = f1 +f2,然后将f2赋值给f1,f的值赋值给f2,完成迭代
			f = f1 + f2;
			f1 = f2;
			f2 = f;
		}
		return f;
	}
		
}</span>

5、编写一个程序,当用户输入一个目录时,该程序能列出该目录下的所有子目录和文件(涉及到IO知识)

<span style="font-size:18px;color:#333333;">public class demo32 {
	public static void main(String[] args) {
		//Scanner sc = new Scanner(System.in);
		//String path = sc.next();
		//sc.close();
		int level = 0;
		printFiles(new File("E:\\demo"),level);
	}
	public static void printFiles(File dir,int level) {
		if(!dir.exists()){
			System.out.println("文件不存在");
			return;
		}
		level++;
		File[] files = dir.listFiles();
		for (File file : files) {
			if(file.isDirectory()){
				for(int i=0;i<level;i++){
					System.out.print("    ");
				}
				System.out.println("|---"+file.getName());
				printFiles(file,level);
			} else {
				for(int i=0;i<level;i++){
					System.out.print("    ");
				}
				System.out.println("|---"+file.getName());
			}
		}
	}
}</span>

6、输入两个整数m,从数列123.......n 中随意取几个数使其和等于m ,要求将其中所有的可能组合列出来.

<span style="font-size:18px;color:#333333;">public class Comp {
    static void getAllComp (int n,int m){
    	String pre = m+"=";
    	int theMax = (1+n)*n/2;
    	if(theMax<m){
    	System.out.println("不存在该数!");
    	}else{
    		for(int i=1;i<=m/2;i++){
    //从 1 开始计数,打印出两个数的组合,并且两数不相等
    			if(i != m-i && n>=m-i);
    			System.out.println(pre+i+"+"+(m-i));
    //调用递归,继续求得大于 2 个数的组合
    			getTheResult(m-i,pre+i,i,n);

    		}
    	}
    }

//调用递归,继续求得大于 2 个数的组合,j 为组合中已用过的数,所以取大于该数
    static void getTheResult(int m,String pre,int j,int n){
    	for(int i=j+1;i<=m/2;i++){
    		if(i != m-i && n>=m-i)
    			System.out.println(pre+"+"+i+"+"+(m-i));
    		getTheResult(m-i,pre+"+"+i,i,n);
    	}
    }
    
    public static void main(String[] args) {
    	getAllComp(6,10);
    	}
}

//	10=1+9
//	10=1+2+3+4
//	10=1+3+6
//	10=1+4+5
//	10=2+8
//	10=2+3+5
//	10=3+7
//	10=4+6
//	10=5+5</span>



















  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值