赞
踩
各位朋友们,大家好!
因为我最近接触的感觉有难度的算法题一部分可以用递归进行解决,并且递归对于数据结构的学习也很重要,所以我今天总结了一下最近对递归的学习总结!
一个问题可拆分为若干个子问题的解
拆分后的子问题与原问题除问题规模不同,解决思路相同
存在递归的起始条件(无起始条件就会陷入死循环)
注意: 所谓起始条件就是不借助任何其他方法,就能直接知道求出问题答案
计算机科学中,递归是一种解决计算问题的方法(但他只是方法之一),其中解决方案取决于同一类问题的更小子集(方法自己调用方法自己,而方法里面调用别的方法,就不是解决同一类问题了)
<1>.所谓递归就是有递并且还会存在归,所谓递就是你在调用自身方法,而归就是你执行完毕通过起始条件来进行由递到归的转换
<2>.递的次数和归的次数是一样的,并且递的顺序和归的顺序相反(比如上图递的过程是n(0-4) 而归的过程就是n(4-0) )
<3>.上同为例,其中起始条件(由递到归的条件)是n==4,而递的过程就是0-4,归的过程就是4-0
<4>.从栈的角度来看:递是进栈,而归就是出栈
package ITHeiMaTest; /* * 定义一个字符串进行反向打印 * */ public class Demo { public static void main(String[] args) { String str = "TSIzwza"; //方法一:利用字符缓冲 StringBuffer sb = new StringBuffer(str); System.out.println(sb.reverse()); //第二种方法使用递归实现 reverse(0,str); } public static void reverse(int n ,String str){ if (n == str.length()){ return ; } reverse(n + 1,str); System.out.print(str.charAt(n)); } }
上题答案如上!(并且我也写了一个字符缓冲流的API进行了书写转换)
接下来我会通过几个例题来进行书写递归
1.单路递归
递归解决冒泡排序
package ITHeiMaTest; import java.util.Arrays; /* * 利用递归输出冒泡排序 * */ public class Demo { public static void main(String[] args) { int[] arr = {4,2,6,8,3}; bubble(arr, arr.length - 1); System.out.println(Arrays.toString(arr)); } //j表示未排序区间的右边界 public static void bubble(int[] arr, int j){ //结束条件j左边无元素 if (j == 0){ return; } for (int i = 0; i < j; i++) { //大的往上走 if (arr[i] > arr[i + 1]){ int t = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = t; } } bubble(arr, j - 1); } }
上述代码存在一些时间上的浪费
上述你在排第一次(2和1)过后就有序了,但是这轮冒泡结束后但是递归过程没有结束,因为你的j并没有=0,他会持续进行直到j=0,而你后面进行的递归完全就属于无用功,因此我下面会书写提前结束递归对冒泡排序的优化
只需要定义一个变量作为排序和未排序的分界线即可
1.赋值规则:定义一个变量x,如果发生交换就把i索引的值赋值给x,如果没有发生交换x的值保持不变
2.为什么x是有序和无序的边界:冒泡排序中俩个元素发生了交换就表示有无序的情况,那么没有发生交换就表示有序,如果最后一次发生交换就是意味着后面的都是有序的,因为你是最后一次交换,后面没有发生交换,此时最后一次交换时候的x就表示有序和无序的分界线,所以优化了上边的冒泡现在你只需要考虑x左边的了,右边的并不需要考虑,上面的是j--表示有边界,而优化后的就是x表示右边界
package ITHeiMaTest; import java.util.Arrays; /* * 对于冒泡排序进行优化 * 引进一个变量x 来作为有序和无序的分界线 * * */ public class DemoNice { public static void main(String[] args) { int[] arr = {4,2,6,8,3}; bubble(arr, arr.length - 1); System.out.println(Arrays.toString(arr)); } //j表示未排序区间的右边界 public static void bubble(int[] arr, int j){ //结束条件j左边无元素 if (j == 0){ return; } //此时的x表示有序和无序的分界线 x的右边为有序 x的左边为无序 int x = 0; for (int i = 0; i < j; i++) { //大的往上走 if (arr[i] > arr[i + 1]){ int t = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = t; //只要发生了交换x就往前移动 //而x后面没发生交换的一定是有序的 x = i; } } bubble(arr, j - 1); } }
2.多路递归
多路递归也就是会分叉的递归(包含多个自身调用)
多路递归一般都比较复杂,不建议使用,建议使用递推(多路递归执行的代码很多都是重复的)
因为一个路没有运行完,下个路根本执行不了(上述的f5中一条支路没有走完,另一条支路不会执行)
起始条件和递推关系:
package ITHeiMaTest; /* * 用递归求斐波那契数列 * */ public class Demo1 { //递归求斐波那契次数十分麻烦 (次数为:2 * f(n + 1) - 1) //多路递归一般都比较复杂,主要原因就是一个路未执行完,另外一个路无法继续执行 //多路递归也就是(分叉递归) public static void main(String[] args) { int x = sum(16); System.out.println(x); } private static int sum(int n) { //递到归的转换条件 if (n == 0){ return 0; } if (n == 1){ return 1; } int x = sum(n - 1); int y = sum(n - 2); return x + y; } }
上述的斐波那契可以用空间的浪费代替时间的浪费(就是用数组进行优化)
利用一维数组进行优化(二维数组也可以优化同理)
package ITHeiMaTest; import java.util.Arrays; /* * 对斐波那契数列进行优化 * */ public class Demo2 { public static int fibonacci(int n){ int[] cache = new int[n + 1]; Arrays.fill(cache, -1); cache[0] = 0; cache[1] = 1; return f(n,cache); } private static int f(int n, int[] cache) { if (cache[n] != -1){ return cache[n]; } int x = f(n - 1,cache); int y = f(n - 2,cache); cache[n] = x + y; return cache[n]; } public static void main(String[] args) { System.out.println(fibonacci(5)); } }
这是我认为的一道很好的关于递归的题(汉罗塔)
package ITHeiMa; /* * 递归实现汉罗塔 * */ import java.util.Arrays; import java.util.LinkedList; public class Demo1 { //a b c表示三个柱子 //a 表示 原柱子 //b 借助的柱子 //c 目标的柱子 static LinkedList<Integer> a = new LinkedList<>(); static LinkedList<Integer> b = new LinkedList<>(); static LinkedList<Integer> c = new LinkedList<>(); public static void main(String[] args) { init(3); print(); move(3,a,b,c); } //添加元素(n圆盘的个数) public static void init(int n){ for (int i = n; i >= 1; i--) { a.addLast(i); } } public static void move(int n, LinkedList<Integer> a, LinkedList<Integer> b, LinkedList<Integer> c){ if (n == 0){ return; } //将盘子由a 借助 c 移动到 b move(n - 1, a , c , b); //表示最后一个盘子移动到c c.addLast(a.removeLast()); //将盘子由b 借助 a 移动到 c move(n-1, b , a , c); print(); } public static void print() { System.out.println(a); System.out.println(b); System.out.println(c); System.out.println("-------------"); } }
今天是我第一次写博客,会有很大的问题,如有什么错误,欢迎大佬在评论区指错,我一定会虚心听取努力进行改正
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。