ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

递归

2022-06-16 22:32:05  阅读:120  来源: 互联网

标签:arr 递归 int num front public


递归

总结:递归是一个思想,自己调用自己的一个过程

要点:

  1. 一定要有一个出口(结束条件)
  2. 写出每次重复要做的代码 包括调用自己的时机
  3. 递归的层级不易过多(栈溢出)

分析:

  1. 出口:

    这个出口可以是明确的 比如说当满足特定的一个数值 如自然数的和 或阶乘中

    也可以是隐藏的

    1. 比如递归文件操作时 file.listFiles() 的返回值 可能是 null 当为null时 也就不会在调用自身

    此时是 在获得 最后一层的文件夹的 list 这时将不会在产生list 集合 递归停止(不会在调用自身)

    1. 比如 汉诺塔中 if(floors==1){}else{递归} 当层数为1时 就不再会取调用自身
  2. 调用时 是否要参数-1

    这取决于你的 每次重复要做的代码是 如何书写的 如例子2 中的 实现循环功能1

    其实 调用的代码也是属于 每次要重复执行的 代码

    每次重复要做的代码 是不是和for while循环体一样 所以 递归的功能 是循环

3.书写递归就是

找出什么时候不再 调用自己本身的条件 和 书写需要循环执行的代码 代码需要逻辑严密

4.注意事项

​ 1.当两个方法相互调用时 可能出现 间接的 递归调用 可以设一个计数器来 标记调用的次数 防止栈溢出

​ 2.递归时的判断条件 > 和>= 或需要深思熟虑 有可能平时没注意的细节 导致递归 不但预期 如二分法求元素再数组中的位置 ,当递归时 +1 -1 和判断条件是>=或结果是有区别的

  1. 递归的内存图和执行图

例子1-递归格式

/*
求连续自然数和 阶乘
*/
public class Recursion1 {
    //递归调用
    public static int sum(int num) {
        if (num == 1) {
             return  1;//递归出口
        }
        int sum =num+sum(num-1);//本次需要执行的代码
        return sum;
    }
    //普通方法 --for循环
    public static int sum1 (int num){
        int sum =0;
        for (int i = 1; i <= num; i++) {
            sum+=i;
        }
        return sum;
    }
    public static void main(String[] args) {
        System.out.println("sum(10) = " + sum(10));
        System.out.println("sum1(10) = " + sum1(10));
    }
}

例子2-递归功能 循环

public class One2One {
    //递归-实现循环功能1
    public void printNumTimes( int num){
        if(num==1)return ;
        System.out.println("好好学习,天天向上");
        num--;
        printNumTimes(num);
    }
    //打印1000-9999中的回文数字
    //会报StackOverflowError 递归的层次太深 :感觉不是 应该是对象的引用创建的太多了
    public void printNums(int num){
        if (num==10000)return;
        String str = num+"";
        String s = new StringBuilder(str).reverse().toString();
        if (str.equals(s)){
            System.out.println(str);
        }
        printNums(num+1);
    }
    public static void main(String[] args) {
        One2One  one = new One2One();
        one.printNumTimes(10);
        System.out.println("----------------");
        one.printNums(1000);
    }
}

例子3-递归实现斐波那契数列

public class FibonacciSequence {
    /*
        数列: 1、1、2、3、5、8、13、21、34...
        求第第12个数是多少
    */
    //普通
    public int method(int num_th) {
       /*
            想要求第12 必须知道 第11 和 第10个 ...
            用变量保存 前1个 前2个 会丢失
            比如说 求 第11 的时候 变量记录的值  为第10个和第9个数的值    第11个数 和第10个数 将会丢失
            使用数组保存数列
        */
        int [] arr = new int[num_th];
        arr[0]=1;
        arr[1]=1;
        for (int i = 2; i < num_th; i++) {
            arr[i]=arr[i-1]+arr[i-2];
        }
        return arr[num_th-1];
    }
    //递归 第n次的数量 = 第n-1次的数量+第n-2次的数量 method(int i) 就是求某次的数量
    public int method2(int i){
        if(i==1)return 1;
        if (i==2)return 1;
        return method2( i-1)+method2(i-2);
    }
    public static void main(String[] args) {
        FibonacciSequence fq = new FibonacciSequence();
        System.out.println("fq.method(12) = " + fq.method(12));
        System.out.println("fq.method2(12) = " + fq.method2(12));
    }
}

例子4-求文件夹中文件的全部大小

import java.io.File;
//求某个文件夹中的文件大小 (文件夹"没有大小"只是一个管理工具)  这个就没有明显的出口
public class CountFileSize {
    //这个方法的功能是求文件夹中文件的大小
    public int getSize(File file){
        int sum=0;//记录文件中文件的大小
        File[] files = file.listFiles();//获得文件夹中 所有的文件(文件和文件夹)
        if (files!=null){
            for (int i = 0; i < files.length; i++) {
                if(files[i].isFile()){
                    sum+=files[i].length();//如果是文件就 累积大小
                }else {
                    sum+=getSize(files[i]);//如果是文件夹就 就用统计好的 + 文件夹的大小
                }
            }
        }
        return sum;//最后返回统计的大小
    }
    public static void main(String[] args) {
        File file = new File("E:\\itheima\\homework\\作业");
        CountFileSize countFileSize = new CountFileSize();
        System.out.println(countFileSize.getSize(file)+"b");
    }
}

例子5-汉诺塔问题

//问题的描述请百度 这个原来是有明显出口的(比如if...retrun...) 后来自己改了
public class Hanoi {
    int count=0;
    public void innit(int floors,String A,String B ,String C){
        if(floors==1){
            move(floors,A ,C);
            count++;
        }else {
            innit(floors-1,A,C,B);//这里递归调用 看参数的位置即可 实际移动的都是调用move方法
            move(floors,A,C);
            innit(floors-1,B,A,C);//这里递归调用 看参数的位置即可 实际移动的都是调用move方法
        }
    }
    private void move(int floors, String A, String C) {
        System.out.println("移动第"+floors+"层,从"+A +"到"+C);
    }
    public static void main(String[] args) {
        Hanoi hanoi = new Hanoi();
        long l = System.currentTimeMillis();
        hanoi.innit(24,"A柱","B柱","C柱");
        long l2 = System.currentTimeMillis();
        System.out.println("一共移动了"+hanoi.count+"次");
        System.out.println(l2-l+"ms");
    }
}

例子6-二分法查找数组中是否有某个元素

//二分查找要求 数组中的元素 必须有效 升序 或 降序都可以 下面方法中的判断是基于升序数组的
public class BinarySearch {
    //递归
    public int binary(int findNum,int [] arr,int left,int right){
        int mid=(left+right)/2;
        if (left>right)return -1;//递归到了出口表示 左右 中间下标的值都不等于 查找值 没有查找到值
        if(findNum>arr[mid]){
            return binary(findNum,arr,mid+1,right);
        }else if (findNum<arr[mid]){
            return binary(findNum,arr,left,mid-1);
        }else {
            return mid;
        }
    };
    //普通
    public int binary2(int findNum,int [] arr,int left,int right){
        while(true){
            int mid=(left+right)/2;
            if(findNum>arr[mid]){
                left=mid+1;
            }else if (findNum<arr[mid]){
                right=mid+1;
            }else {
                return mid;
            }
            if(left>right){
                break;
            }
        }
        return -1;
    };
    public static void main(String[] args) {
        //, 17, 18, 30, 39, 42, 51, 57, 58, 59, 66, 69, 69, 76, 78, 100
        int [] arr = {2, 4, 6, 9, 14};
        BinarySearch binarySearch =new BinarySearch();
        int recursion = binarySearch.binary(15, arr, 0, arr.length - 1);
        int poor = binarySearch.binary2(15, arr, 0, arr.length - 1);
        System.out.println("recursion = " + recursion);
        System.out.println("poor = " + poor);
    }
}

例子7-快速排序

import utils.ArrOpe;
import java.util.Arrays;
public class QuickSort {
    public void quick(int[] arr) {
        quick0(arr, 0, arr.length-1);
    }
    /*
     1.选取中心轴
     2.右边开始找到第一个 小于中心轴的数的下标
     3.左边开始找到第一个 大于中心轴的数的下标
     4.如果 下标不相等 交换 第一个 左右的数 继续找第二个
             下标相等 交换 较小值下标 和 基准下标
     5.递归
     */
    public void quick0(int[] arr, int begin, int end) {
        if (begin>=end){//有可能在递归时 +1 -1 是的 begin>end
            return;
        }
        int base = arr[begin];
        int front = begin ;//front 前面 这里不能加1 对于排好序的会导致 这次front=behind=下标1 而base=下标0 if交换时 再次乱序
        int behind = end;// behind 后面
        while (true) {
            //1.从后往前 找到第一个较小值下标
            while (arr[behind] >= base && behind > front) {
                behind--;
            }
            //2.从前往后找打第一个较大值下标
            while (arr[front] <= base && behind > front) {
                front++;
            }
            if (front != behind) {//如果 前后小标不相等  表示 这轮没有执行完 还有较小的没放左边 较大的没放右边
                arr[front] = arr[front] ^ arr[behind];
                arr[behind] = arr[front] ^ arr[behind];
                arr[front] = arr[front] ^ arr[behind];
            } else {//如果相等 表示 这轮比较完毕 把 较小值和 基准值互换位置
                //细致 说是 如果是前往后 没找到较大值 此时前后下标重合 那么基准是和 这轮的某次 较小互换位置
                //         如果是后往前 没找到较小值 此时前后下标重合 那么基准是和 上轮的最后一次 较小互换位置
                arr[begin] = arr[front];
                arr[front] = base;
                break;
            }
        }
        quick0(arr, begin, front - 1);
        quick0(arr, front + 1, end);
    }
    public static void main(String[] args) {
        QuickSort quickSort = new QuickSort();
        int[] arr = ArrOpe.getArr(100, 20);
        System.out.println("排序前:"+Arrays.toString(arr));
        quickSort.quick(arr);
        System.out.println("排序后:"+Arrays.toString(arr));
    }
}

例子8-求八皇后问题--学习中

public class ...

标签:arr,递归,int,num,front,public
来源: https://www.cnblogs.com/acman-mr-lee/p/16383814.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有