算法期末整理——递归篇

算法期末整理——递归篇



一、定义

1、在调用一个函数的过程中又出现直接或间接调用该函数本身,称为函数的递归(Recursion)调用,这种函数称为递归函数
2、若p函数定义中调用p函数,称之为直接递归。若p函数定义中调用q函数,而q函数定义中又调用p函数,称之为间接递归

二、递归要素

在这里插入图片描述

三、递归特点

1、优点

结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性,因此它为设计算法、调试程序带来很大方便。

2、缺点:

递归算法的运行效率较低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多。
注:在某些递归算法中可消除递归调用,使其转化为非递归算法。

四、使用递归

1、能用递归解决的问题应该满足

(1) 可以转化为一个或多个子问题来求解,而这些子问题的求解方法与原问题完全相同,只是在数量规模上不同。
(2) 递归调用的次数必须是有限的。
(3) 必须有结束递归的条件来终止递归。

2、何时使用递归

(1) 定义是递归的(阶乘、斐波那契数列等)。
(2) 数据结构是递归的(单链表、二叉树等)。
(3) 问题的求解方法是递归的(汉诺塔、回溯法等)。

五、经典案例

1、求阶乘

在这里插入图片描述

package recursion;

import java.util.Scanner;

//阶乘函数
public class test1 {

	public static void main(String args[]){
		int n;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			n = sc.nextInt();
			fac(n);
			System.out.println(fac(n));
		}
	}
	public static int fac(int n){
		if(n==0)
			return 1;
		return n*fac(n-1);
	}
}

2、斐波那契数列

在这里插入图片描述

package recursion;

import java.util.Scanner;

//斐波那契数列
public class test2 {
	public static void main(String args[]){
		int n;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			n = sc.nextInt();
			Fibonacci(n);
			System.out.println(Fibonacci(n));
		}
	}
	public static int Fibonacci(int n){
		if(n<=1)
			return 1;
		return Fibonacci(n-1)+Fibonacci(n-2);
	}
}
例1 青蛙跳台阶

问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法?
解决:符合Fibonacci数列规律,用其求解。
代码:略。

例2 铺地板

问题:对于一条长为2×n的长方形过道,需要用1×2的瓷砖铺满,求铺设方案的数量m。例如:当n=3时,过道为2×3的长方形,瓷砖的铺设方案共有三种,如下图所示。
在这里插入图片描述
解决:符合Fibonacci数列规律,用其求解。
代码:略。

例3 XP的楼梯

问题:XP是个淘气的孩子,他最近迷上了跳楼梯。他可以一次跳一级,也可以一次跳两级,他居然还能够一次跳三级楼梯(危险动作,请勿模仿)。某次,XP在跳完楼梯后突然想到一个问题,如果有n级楼梯,他从第一级开始往上跳,一直跳到第n级共有多少种不同的方案?你能帮他解决这个问题吗?当然,如果只有一级楼梯,很明显他只有一种选择。
解决:符合Fibonacci数列的类似规律。

package recursion;

import java.util.Scanner;

public class test5 {

	public static void main(String args[]){
		int n;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			n = sc.nextInt();
			fac(n);
			System.out.println(fac(n));
		}
	}
	public static int fac(int n){
		if(n==1)
			return 1;
		if(n==2)
			return 1;
		if(n==3)
			return 2;
		if(n>3)
			return fac(n-1)+fac(n-2)+fac(n-3);
		return 0;
	}
}
例4 一只小蜜蜂

问题:有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。其中,蜂房的结构如下所示。
在这里插入图片描述
输入整数a和b表示起点和终点,输出a到b可能的线路数。例如:输入1和2,输出1;输入3和6,输出3。
解决:符合Fibonacci数列规律。

import java.util.Scanner;

public class Main{
	public static void main(String args[]){
		int a,b,n,s;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			a = sc.nextInt();
			b = sc.nextInt();
			n = b-a;
			s = fibonacci(n);
			System.out.println(s);
		}
	}
	public static int fibonacci(int n){
		if(n<=1)
			return 1;
		else
			return fibonacci(n-1)+fibonacci(n-2);
	}
}

3、汉诺塔问题

在这里插入图片描述

package recursion;

import java.util.Scanner;

//汉诺塔问题
public class test3 {
	static int m = 1;
	public static void main(String args[]){
		int n;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			n = sc.nextInt();
			char a = 'A';
			char b = 'B';
			char c = 'C';
			m = 1;
			hanoi(n,a,b,c);
			System.out.println();
            //注意换行
		}
	}
	public static void hanoi(int n,char a,char b,char c){
		if(n>0){
			hanoi(n-1,a,c,b);
			move(n,a,c);
			hanoi(n-1,b,a,c);
		}
	}
	public static void move(int n,char a,char c){
		System.out.println("第"+m+++"步:"+n+"号盘从"+a+"柱移至"+c+"柱");
		//第1步:1号盘从A柱移至C柱,注意符号:
	}
}

4、整数划分

求正整数n的不同划分个数,比如4的划分为下图情况。
在这里插入图片描述
在这里插入图片描述

package recursion;

import java.util.Scanner;
//整数划分
public class test10 {
	public static void main(String args[]){
		int n,m;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			n = sc.nextInt();
			m = sc.nextInt();
			up(n,m);
			System.out.println(up(n,m));
		}
	}
	public static int up(int n,int m){
		if(n<1||m<1)
			return 0;
		if(n==1||m==1)
			return 1;
		if(n<m)
			return up(n,n);
		if(n==m)
			return up(n,n-1)+1;
		return up(n,m-1)+up(n-m,m);
	}
}

5、全排列问题

例1 字母全排列

问题:编写一个程序,使用递归算法输出一个一维字符数组中所有字符的全排列,假设字符都不一样。例如{‘a’,‘b’,‘c’}的全排列为(a,b,c), (a,c,b), (b,a,c), (b,c,a), (c,a,b), (c,b,a)。

package recursion;

import java.util.Scanner;

public class test7 {
	public static void main(String args[]){
		int n;
		char[] list = new char[]{'a','b','c','d','e','f',
				'g','h','i','j','k','l','m','n','o','p',
				'q','r','s','t','u','v','w','x','y','z'};
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			n = sc.nextInt();
			allist(list,0,n);
		}
	}
	public static void allist(char list[],int k,int n ){
		int i ,j;
		char t;
		if(k==n){
			for(i=0 ; i<n ; i++){
				System.out.print(list[i]);
			}
			System.out.println();
		}
		for(j=k ; j<n ; j++){
			{
				t = list[k];
				list[k] = list[j];
				list[j] = t;
			}
			allist(list,k+1,n);
			{
				t = list[j];
				list[j] = list[k];
				list[k] = t;
			}
		}
	}
}

例2 1-9加法

问题:使用1-9这9个数字,每个数字各出现一次,如何组成如下数学公式:□□□ + □□□ = □□□。即:组成三个三位数,其中两个数之和等于第三个数。
代码:略。

例3 九组数分数

问题:使用1-9这9个数字,每个数字各出现一次。如何组成一个分数,其值恰好为1/3?

package recursion;

import java.util.Scanner;

public class test9 {
	static int a,b;
	static int[] arr = new int[2];
	static int c = 0;
	public static void main(String args[]){
		int list[] = {1,2,3,4,5,6,7,8,9};
		Scanner sc = new Scanner(System.in);
			a = list[0]*1000+list[1]*100+list[2]*10+list[3];
			b = list[4]*10000+list[5]*1000+list[6]*100+list[7]*10+list[8];
			alllist(list,0);
	}
	public static void alllist(int list[],int k){
		if(k==list.length){
			//a,b要在这里面赋值才有结果出来。
			a = list[0]*1000+list[1]*100+list[2]*10+list[3];
			b = list[4]*10000+list[5]*1000+list[6]*100+list[7]*10+list[8];
			if(a*3==b){
				System.out.println(a+"/"+b);//结果按顺序排,这里没排懒。
			}
		}
		int i,t;
		for(i=k ; i<list.length ; i++){
			{
				t = list[k];
				list[k] = list[i];
				list[i] = t;
			}
			alllist(list,k+1);
			{
				t = list[i];
				list[i] = list[k];
				list[k] = t;
			}
		}
	}
}

6、补充

例1 递归求和

问题:使用递归编写一个程序,求以下数列的前n项:s=1-1/2+1/3-1/4+1/5-1/6+…

package recursion;

import java.text.DecimalFormat;
import java.util.Scanner;

//oj练习2D题
public class test4 {

	public static void main(String args[]){
		double n;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			n = sc.nextDouble();
			DecimalFormat df = new DecimalFormat("0.000000");//注意:精确到小数点后六位
			System.out.println(df.format(sum(n)));
		}
	}
	public static double sum(double n){
		if(n==1)
			return 1;
		if(n>1)
			return sum(n-1)+Math.pow(-1, n-1)*(1/n);
		return 0;
	}
}
例2 数字求和

问题:使用递归编写一个程序,计算一个正整数中所有数字之和。例如输入234,输出9。

package recursion;

import java.util.Scanner;
//oj练习2F题
public class test6 {
	public static void main(String args[]){
		int n;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			n = sc.nextInt();
			System.out.println(take(n));
		}
	}
	public static int take(int n){
		int s = n%10;
		if(n<10)
			return s;
		if(n>=10)
			return s+take(n/10);
		return 0;
	}
}
例3 倒序输出

问题:使用递归编写一个程序,逆序输出一个正整数。例如输入1234,输出4321(不含前导0)。

package recursion;

import java.util.Scanner;

public class test8 {
	static  int a = 0;
	static  int b = 0;
	public static void main(String args[]){
		int n;
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			n = sc.nextInt();
			a = b = 0;
			p(n);
			System.out.println();
		}
	}
	public static int p(int n){
		int s = n%10;
		if(n<10){
			System.out.print(s);
		}else{
			if(s==0&&a==b){
				a++;
				b++;
			}else{
				b++;
				System.out.print(s);
			}
			return p(n/10);
		}
		return 0;
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值