一,概念
直接或间接地调用自身的算法称为递归算法。
用函数自身给出定义的函数称为递归函数。
二,实例
实例1:阶乘函数。
通过分析可知,要求一个数的阶乘,只要知道它前一位数的阶乘便可求出。 即:n!=n*(n-1)!
而要求前一位数的阶乘,只要知道它前前一位数的阶乘即可,即:(n-1)!=(n-1)*(n-2)!,因为每次
计算的方式都相同,所以考虑用递归的方式求解。
递归关系:f(n)=n*f(n-1)
递归结束条件:n=1 (因为我们很容易知道1阶乘是1,因此求解其他数的阶乘时,可从1的阶乘开始求起)
代码实现:
1 import java.util.*; 2 public class HW8 { 3 public static void main(String[] args) { 4 Scanner in=new Scanner(System.in); 5 System.out.println("请输入所要求的数值:"); 6 int n=in.nextInt(); //输入所要遍历的数 7 int number=funtion(n); 8 System.out.println(n+"的阶乘为:"+number); 9 10 } 11 12 /** 13 * 求第n个数的阶乘!!! 14 * @param n 所要求的数的值 15 * @return 所要求的数的阶乘 16 * 递归函数结束条件:n<=1 17 */ 18 private static int funtion(int n) { 19 if(n==1) //递归函数的结束条件 20 { 21 return 1; 22 }else{ 23 return n*funtion(n-1); 24 } 25 26 } 27 }
运行结果:
实例2:
用递归判断一个数组是否是一个递增序列的数组。
代码实现:
1 import java.util.*; 2 public class HW8 { 3 public static void main(String[] args) { 4 5 int[] arr = new int[20]; //定义一个可存放20个元素的数组 6 Random rd = new Random(); 7 for (int i = 0; i < arr.length; i++) //对数组随机赋值 8 { 9 arr[i] = rd.nextInt(50) + 1; //范围:1-50 10 } 11 System.out.println(Arrays.toString(arr)); //对arr数组进行打印 12 Arrays.sort(arr); //对arr数组进行排序 13 System.out.println(Arrays.toString(arr)); //对排完序的数组进行打印 14 boolean flag = funtion(arr); 15 if (flag) { 16 System.out.println("该数组是一个有序数组!!!"); 17 } else { 18 System.out.println("无序数组!!!"); 19 } 20 } 21 22 /** 23 * 求该数组是否为一个增序数组 24 * 25 * @param arr 所要验证的数组 26 * @return 增序:true 无或减序:false 27 */ 28 private static boolean funtion(int[] arr) { 29 int index = 0; 30 return funtion2(arr, index); //因为对数组进行递归时,要让数组的长度不断减小 31 //所以要借助下标 32 } 33 34 private static boolean funtion2(int[] arr, int index) { 35 if (index == arr.length - 1) { //如果数组小标等于数组长度-1,则说明对数组元素遍历完了 36 return true; //且中途没有出现乱序,此时返回true 37 } else { 38 if (arr[index] >arr[index + 1]) { //出现非增序列,直接返回false 39 return false; 40 } else { 41 return funtion2(arr, index+1); //若前面排序正常,则调用方法继续检测后面的数组元素 42 } //此时下标+1 43 } 44 45 46 } 47 48 }
运行结果:
实例3:
( 用递归求解字符串中,字符的个数。)
通过分析可知,要求解一个字符串str的长度值,首先应知道str.length()-1的值,而要知道str.length()-1的值,
则要先知道str.length()-2的值,由此不断的递归,可知,知道str-(str.length()-1)的值,即:1,则可求出整个
字符串的长度。
递归关系:f(n)=f(n-1)+1
递归结束条件:index=str.length()-1; (当下标移动到最后一个下标时,则说明整个字符串已被统计完)
代码实现:
1 import java.util.*; 2 public class HW8 { 3 public static void main(String[] args) { 4 Scanner in=new Scanner(System.in); 5 System.out.println("请输入一个字符串:"); 6 String str=in.nextLine(); 7 int number=count(str); 8 System.out.println("统计该字符串的长度为:"+number); 9 10 } 11 12 /** 13 * 求解字符串中,字符的个数。 14 * @param str 所要求解的字符串 15 * @return 所统计的字符个数 16 */ 17 private static int count(String str) { //将所要求解的字符串传给该方法 18 int index=0; //因为要统计字符串的个数,必须要借助下标 19 return count2(str,index); //所以在次调用方法count2 20 } 21 22 private static int count2(String str, int index) { 23 if(index==str.length()-1) //当下标移动到最后一个位置时,则统计完成 24 { 25 return 1; 开始返回,实现“归” 26 }else{ 27 return count2(str,index+1)+1; //当下标还没移动到最后一个位置时,该位置的字符串长度为:(比它少一位的字符串段长度)+1 28 } 29 } 30 }
运行结果:
实例4:(用递归实现有序数组的二分搜索)
通过分析可知,要对一个数组进行二分搜索,首先要求解出该数组中间值,将所查找的数与该
中间数进行比较,若相等则返回该中间值下标。若小于则将middle-1的值赋给right,将范围进行缩减,
然后又开始执行上述操作。若大于则将middle+1的值赋给left,将范围进行缩减,然后又开始执行上述操作。
1 import java.util.*; 2 public class HW8 { 3 public static void main(String[] args) { 4 int[] arr = new int[10]; //定义一个可存放10个元素的数组 5 Scanner in=new Scanner(System.in); 6 Random rd = new Random(); 7 for (int i = 0; i < arr.length; i++) //对数组随机赋值 8 { 9 arr[i] = rd.nextInt(50) + 1; //范围:1-50 10 } 11 System.out.println(Arrays.toString(arr)); //对arr数组进行打印 12 Arrays.sort(arr); //对arr数组进行排序 13 System.out.println(Arrays.toString(arr)); //对排完序的数组进行打印 14 System.out.println("请输入所要查找的数:"); 15 int number=in.nextInt(); 16 int index=binarySearch(arr,number,0,arr.length-1); 17 if (index==-1) { 18 System.out.println("没有查找到该数!!!"); 19 } else { 20 System.out.println("所要查找的数为:"+arr[index]+"该数的下标为"+index); 21 } 22 } 23 24 /** 25 * 26 *用递归实现有序数组的二分搜索 27 * @param arr 进行搜索的数组 28 * @number 要查找的数 29 * @left 开始下标 30 * @right 结束下标 31 * @return 若找到返回下标,否则返回-1 32 * 递归结束条件:left>right 33 */ 34 private static int binarySearch(int[] arr,int number,int left,int right) { 35 int middle=(left+right)/2; 36 if(left>right) 37 { 38 return -1; 39 }else{ 40 if(arr[middle]==number) 41 { 42 return middle; 43 }else if(arr[middle]>number) 44 { 45 //right=middle-1; 为简缩代码一般将该语句放在下次调用方法的赋值中 46 return binarySearch(arr,number,left,middle-1); 47 }else{ 48 //left=middle+1; 49 return binarySearch(arr,number,middle+1,right); 50 } 51 52 } 53 54 } 55 }
运行结果:
递归调用过程:
实例5:
用递归解决下面问题:
有三种面值的硬币,分别是1分,2分,5分
现在给出一个价值,例如价值为11,问组成该价值至少需要的硬币数量是多少???
1 import java.util.*; 2 public class HW8 { 3 public static void main(String[] args) { 4 Scanner in=new Scanner(System.in); 5 System.out.println("请输入硬币的价值:"); 6 int value=in.nextInt(); 7 int count=fountion(value); 8 System.out.println("至少需要的硬币数量:"+count); 9 } 10 11 private static int fountion(int value) { 12 if(value>=5) 13 { 14 return 1+fountion(value-5); 15 }else if(value<5&&value>=2) 16 { 17 return 1+fountion(value-2); 18 }else if(value>=1&&value<2) 19 { 20 return 1; 21 }else
22 {
23 return 0;
24 }
24 }
25 }
价值 至少需要的硬币数量
1 1
2 1
3 2
4 2
5 1
6 2
~ ~
通过观察可知,当硬币数为1,2,5时只需一枚硬币。当硬币数为3,4时,只需2枚硬币数。
当大于5时,用价值-5,继续上述循环。。。。
1 import java.util.*; 2 public class HW8 { 3 public static void main(String[] args) { 4 Scanner in=new Scanner(System.in); 5 System.out.println("请输入硬币的价值:"); 6 int value=in.nextInt(); 7 int count=fountion(value); 8 System.out.println("至少需要的硬币数量:"+count); 9 } 10 11 private static int fountion(int value) { 12 if(value==1||value==2||value==5) 13 { 14 return 1; 15 }else if(value>2&&value<5) 16 { 17 return 2; 18 } 19 return 1+fountion(value-5); 20 21 } 22 }
实例6: (汉诺塔问题)
通过分析可知,对于有n层的汉诺塔问题,可将其看作成两层(上面的i-1层 ,最底1层)来操作,
首先将上面的i-1层从a借助c移动到b,然后将最底下的一层从a直接移到c,最后将b上的i-1层借助a移动
到c。而对于如何将i-1层从a移动到b的问题与上述过程类似,所以调用递归来解决。
1 public class HW8 { 2 public static void main(String[] args) { 3 Scanner in=new Scanner(System.in); 4 System.out.println("请输入汉诺塔的层数:"); 5 int number=in.nextInt(); 6 hanoi(number,'a','b','c'); 7 } 8 9 /** 10 * 求出有n层汉诺塔时的移动过程 11 * @param i 汉诺塔的层数 12 * @param a 起始柱 13 * @param b 辅助柱 14 * @param c 目标柱 15 * 将n层的塔假设成两层,(1层,n-1层) 16 */ 17 private static void hanoi(int i, char a, char b, char c) { 18 if(i>1) 19 { 20 hanoi(i-1,a,c,b); //当为两个时,先将上面的从a移给b (a->b) [此时有很多,所以要借助b] 21 System.out.println(a+"->"+c); //然后将底下的从a移给c (a->c) [因为此时a上只剩一个,直接移动] 22 hanoi(i-1,b,a,c); //然后将b的在移给c (b->c) [此时有很多,所以要借助b] 23 //…………此时就完成了一次的移动过程…………// 24 }else{ 25 System.out.println(a+"->"+c); //当为一个时,直接将a上的移给c (a->c) 26 } 27 28 } 29 }