java递归

前言:

各位朋友们,大家好!

因为我最近接触的感觉有难度的算法题一部分可以用递归进行解决,并且递归对于数据结构的学习也很重要,所以我今天总结了一下最近对递归的学习总结!

一、递归的使用场景

一个问题可拆分为若干个子问题的解

拆分后的子问题与原问题除问题规模不同,解决思路相同

存在递归的起始条件(无起始条件就会陷入死循环)

注意: 所谓起始条件就是不借助任何其他方法,就能直接知道求出问题答案

二、递归的定义

计算机科学中,递归是一种解决计算问题的方法(但他只是方法之一),其中解决方案取决于同一类问题的更小子集(方法自己调用方法自己,而方法里面调用别的方法,就不是解决同一类问题了)

三、例题进行分析

示例1:

思路分析:

<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.单路递归

示例2:

递归解决冒泡排序

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中一条支路没有走完,另一条支路不会执行)

示例3:

起始条件和递推关系:

 

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));
    }
}

示例4:

这是我认为的一道很好的关于递归的题(汉罗塔)

 

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("-------------");
    }
}
 

      今天是我第一次写博客,会有很大的问题,如有什么错误,欢迎大佬在评论区指错,我一定会虚心听取努力进行改正 

  • 54
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 19
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风止￴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值