递归解析

本文介绍了递归算法,它将问题拆分成基本元素,再组合运算结果,效率不高、可读性差,多用于数的遍历。还阐述了其在斐波拉契数列、文件夹遍历、快速排序、八皇后问题中的应用,重点分析了快速排序的过程、时间和空间复杂度及稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、介绍
递归通过拆分成各个基本元素,然后再将基本元素组合运算结果作为下一层的中间值。依此向下拆分,然后不断向上组合,直到完成整个运算。
递归算法效率不高,并且代码可读性差,主要应用于数的遍历场景。
二、几种应用
1.斐波拉契数列
1)利用循环实现
num1 + num2 = num3
num2 + num3 = num4
num4 + num5 = num6

依此类推
可以总结出来
这里运算几次,就是循环几次,然后每次将两者运算结果作为中间变量。第一个变量等于第二个变量,第二个变量等于中间变量。
循环实现:

 	    int num1 = 1;
        int num2 = 1;
        int n = 6;
        //循环方式
        for(int i = 3; i <= n; i++){
            int num3 = num1 + num2;
            num1 = num2;
            num2 = num3;
        }
        System.out.println(num2);

递归实现:

    // 不断递归拆解,然后不断返回
//    f(6)分成f(5)+ f(4)
//    f(5)分成f(4)+f(3)
//    f(4)分成f(3)+f(2)
//    f(3)分成f(2)+f(1)
//    f(2)返回 1
//      f(1)返回1
//      f(3)返回 2
//      f(2) 返回1
//      f(4)返回3
//      接着算f(5)分解出来第二部分f(3)
//      f(3) 拆成 f(2) + f(1)
    public static int fab(int num){
        if(num == 1 || num == 2){
            return 1;
        }
        return fab(num -1) + fab(num -2);
    }

2.文件夹遍历
这里应该属于深度遍历。

    private static void recursiveFile(File file) {
        //获取当前文件夹下所有子文件夹/文件
        for (File f : file.listFiles()) {

            if (f.isFile()) {
                //文件
                System.out.println("文件:" + f.getName());
            } else {
                recursiveFile(f);
            }
        }
    }

3.快速排序
1)介绍
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
2)过程
(1)每次以最左边元素为标杆,然后依次从右到左遍历和从左到右遍历。
(2)当右边遍历过程中发现有比标杆数小的数,就把小的数放到左边遍历到位置,右边停止遍历
(3)然后左边遍历,当发现有比标杆数大的数,就把大的数放到右边遍历到的位置,左边停止遍历
(4)两边遍历直到左右两边遍历到同一个位置结束。然后将标杆数放到这个同一位置上
(5)左边部分重复上面操作,右边部分重复上面操作
3)实现

public class QuickSort {
    //快速排序
    public static void main(String[] args) {
        int[] ints = new  int[]{5,3,6,7,9,2,4,8};
        sort(ints,0,ints.length -1);
        for (int i : ints) {
            System.out.println(i);
        }
    }
    //递归左右两边分别进行递归处理
    private static void sort(int[] ints, int s, int e){
        if(s < e){
            int m = sortUnit(ints,s,e);
            sort(ints,s,m -1);
            sort(ints,m + 1, e);
        }
    }
    private static int sortUnit(int[] ints, int s, int e){
        int tmp = ints[s];
        int i = s;
        int j = e;
//        两边遍历直到同一位置结束遍历
        while(i < j){
            //右边循环,直到碰到有比标杆数小的数
            while(i < j){
                if(ints[j] < tmp){
                    ints[i] = ints[j];
                    break;
                }
                j--;
            }
            //左边循环,知道碰到有比标杆数大的数
            while(i < j){
                if(ints[i] > tmp){
                    ints[j] = ints[i];
                    break;
                }
                i++;
            }
        }
        //左右碰头的位置,为标杆数左右大小区分的位置
        ints[i] = tmp;
        return i;
    }
}

4)时间复杂度
平均时间复杂为O(nlog2 n),最糟糕时将达到O(n²)的时间复杂度
5)空间复杂度
最优的情况下空间复杂度为O(log2 n),每一次都平分数组;最差的情况下空间复杂度为O( n )
6)稳定性
快速排序每次交换的元素都有可能不是相邻的, 因此它有可能打破原来值为相同的元素之间的顺序.
不稳定
4.八皇后
注意每次进行下层遍历,如果没有找到合适位置,就回来清除该层的皇后位置,尝试下一个位置。并且找到一种方式后,也是清除最后一行的皇后位置,就会倒退不断再次尝试寻找新的摆放方式。
实现:

public class EightQueen {
    //八皇后问题
    //八行八列的格子里面,放上一个皇后后,上下左右,左上右上,左下右下都能再放皇后
    //如果这八行都放上皇后,该是什么排列
    //初始化一个八行八列的格子图,,0表示没有皇后,1表示放了皇后
    static int[][] map = new int[8][8];

    public static void main(String[] args) {
        play(0);
    }
    //从某一行开始开始摆放皇后
    private static void play(int row){
        //遍历该行的每个列
        for(int i = 0; i < 8; i++){
//            判断是否有位置可以放皇后
            if(check(row,i)){
                //该位置可以放皇后
                map[row][i] = 1;
                if(row == 7){
                    //如果最后一行都放置了皇后,打印摆列方式
                    show();
                    //这里寻找下一种摆法,只需要把最后一行的皇后清除,这时就会最后一行就会依次尝试摆放皇后,没有找到,就会清除上一层皇后,然后类似清除,尝试,直到找到新的一种摆放方式。
//                    map[row][i] = 0;
                }else{
                    //没有到达最后一行,就继续处理下一行
                    play(row + 1);
//                    如果row+1行中没有可放皇后的位置,就回到这一步,清除row中之前皇后的位置,让循环继续下去,尝试下一个位置时,row+1是否可以摆放。
//                    map[row][i] = 0;//去除皇后
                }
                map[row][i] = 0;
            }
        }
    }
    //展示棋盘落子
    static int count = 1;
    private static void show() {
        System.out.println("第"+count+"种摆法");
        count++;
        for(int i = 0; i < 8; i++){
            for(int j = 0; j < 8; j++){
                System.out.print(map[i][j] + "  ");
            }
            System.out.println();
        }
    }

    //因为是从上往下放,所以当放到第row行时,row下面的肯定没有放,左右也不会放,所以只需要考虑上面三个方向
    private static boolean check(int row, int col){
        //检查上面方向(行数减少,列数不会变)
        for(int i = row -1; i >= 0; i--){
            if(map[i][col] == 1){
                return false;
            }
        }
        //检查左上方向(行数减少,同时列数也减少)
        for(int i = row -1, j = col -1; i >=0 && j >= 0; j-- , i--){
            if(map[i][j] == 1){
                return false;
            }
        }
        //检查右上方向(行数减少,同时列数增加)
        for(int i = row -1, j = col + 1; i >= 0 && j < 8; i--,j++){
            if(map[i][j] == 1){
                return false;
            }
        }

        return true;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值