递归

一、递归的定义

递归就是在运行的过程中调用自己。

递归必须要有三个要素:

  1. 边界条件
  2. 递归前进段
  3. 递归返回段

当边界条件不满足时,递归前进;当边界条件满足时,递归返回

二、求阶乘

package recursion;

import java.util.Scanner;

public class RecursionTest1 {
    public static void main(String[] args) {
        //提示
        System.out.println("请输入一个整数:");
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        //调用一个方法,获取n!
        int rs = getFactoriaFor(n);
        System.out.println("n!是: " + rs);
    }

    //通过循环实现n!
    public static int getFactoriaFor(int n) {
        if (n >= 0) {
            int tmp = 1;
            for (int i = 1; i <= n; i++) {
                tmp = tmp * i;
            }
            return tmp;
        } else {
            return -1;  //负数没有阶乘
        }
    }

    //通过递归的算法实现n!
    public static int getFactorialRecursion(int n) {
        if (n >= 0) {
            if (n == 0) {
                return 1;
            } else {
                int tmp = n * getFactorialRecursion(n - 1);
                return tmp;
            }
        } else {
            return -1;
        }
    }
}

三、求数字三角形的最大路径值

package recursion;

import java.util.Scanner;

/**
 * 数字三角形最大路径计算
 * 1
 * 2 3
 * 4 5 6
 */
public class RecursionTest2 {

    private static int[][] data;  //存放数字三角形的数字
    private static int n;  //三角形的行数

    public static void main(String[] args) {
        //二维数组的初始化
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入数字三角形的高度:");
        n = sc.nextInt();
        //实例化二维数组
        data = new int[n][n];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                System.out.println("请输入第" + i + "行,第" + j + "列的数字");
                data[i-1][j-1] = sc.nextInt();
            }
        }
        System.out.println("--------------数字三角形------------");
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                System.out.print(data[i-1][j-1] + " ");
            }
            System.out.println();
        }
        System.out.println("-------------测试结果--------------");
        int rs;
        rs = maxSum(1, 1);
        System.out.println("结果为:" + rs);
    }

    public static int maxSum(int i, int j) {
        if (i == n) {  //边界条件
            return data[i-1][j-1];
        } else {
            int x = maxSum(i + 1, j);
            int y = maxSum(i + 1, j + 1);
            return Math.max(x, y) + data[i - 1][j - 1];
        }
    }

}


四、递归实现二分查找

分治算法简介:
当我们求解某些问题时,由于这些问题要处理的数据非常多,或求解过程非常复杂,我们往往先把它分解成几个子问题,找到求出这几个自问题的方法后,再找到合适的方法合成求整个问题的解法。如果这几个子问题还比较大,可以将它们再分成更小的子问题,以此类推,直到可以求解为止,这就是分治策略的基本思想。
二分查找就是一个典型的例子,将查找范围分查比查找值大的一部分和比查找值小的一部分,每次递归调用只会有一个部分执行。

package recursion;

public class RecursionTest3 {
    public static void main(String[] args) {
        int[] arr = {1,2,4,6,7,8,9};
        int rs;
        rs = binarySearchRecursion(arr,7,0,6);
        System.out.println(rs);
    }

    public static int binarySearchRecursion(int[] arr, int value, int l, int h) {
        int mid = (h + l) / 2;
        if (value == arr[mid]) {
            return mid;
        } else if (l > h) {
            return -1;
        } else {
            if (value > arr[mid]) {
                return binarySearchRecursion(arr, value, mid + 1, h);
            }
            if (value < arr[mid]) {
                return binarySearchRecursion(arr, value, l, mid - 1);
            }
        }
        return -1;
    }

    //for循环实现二分查找
    public static int binarySearchfor(int[] array, int value) {
        int low = 0;
        int high = array.length-1;
        int mid;
        while (low <= high) {
            mid = (low + high) / 2;
            if (value == array[mid]) {
                return mid;
            } else {
                if (value > array[mid]) {
                    low = mid + 1;
                }
                if (value < array[mid]) {
                    high = mid - 1;
                }
            }
        }
        return -1;  //数组中不存在我们要找的值
    }
}

五、汉诺塔

package recursion;

public class RecursionTest4 {
    public static void main(String[] args) {
        move(3,"A","B","C");
    }

    public static void move(int dish, String from, String tmp, String to) {
        if (dish == 1) {
            System.out.println("将第" + dish + "个盘子从" + from + "移动到目标塔座" + to);
        } else {
            move(dish - 1, from, to, tmp);
            System.out.println("将第" + dish + "个盘子从" + from + "移动到目标塔座" + to);
            move(dish - 1, tmp, from, to);
        }
    }
}

六、归并排序

package recursion;

import java.util.Arrays;

public class RecursionTest6 {
    public static void main(String[] args) {
        int[] rs = mergeSort(new int[] {3, 2, 1}, 0, 2);
        System.out.println(Arrays.toString(rs));
    }

    //实现归并排序
    public static int[] mergeSort(int[] c, int l, int h) {
        if (l >= h) {

        } else {
            int mid = (l + h) / 2;
            mergeSort(c, l, mid);
            mergeSort(c, mid + 1, h);
            //把分出来的子数组归并
            merge(c, l, mid, h);
        }
        return c;

    }

    //实现子数组合并
    public static void merge(int[] c, int l, int mid, int h) {
        int i = l;
        int j = mid + 1;
        int[] tmp = new int[h - l + 1];
        int k = 0;

        //实现合并
        while (i <= mid && j <= h) {
            if (c[i] < c[j]) {
                tmp[k++] = c[i++];
            } else {
                tmp[k++] = c[j++];
            }
        }

        while (i <= mid && j > h) {
            tmp[k++] = c[i++];
        }

        while (i > mid && j <= h) {
            tmp[k++] = c[j++];
        }

        for (int g = 0; g < tmp.length; g++) {
            c[l + g] = tmp[g];
        }
    }
}

七、用栈消除递归

package recursion;

import java.util.Stack;

public class RecursionTest7 {
    public static void main(String[] args) {
        System.out.println(addn(3));
        System.out.println(addn1(3));
    }

    //求1+2+3+...+n的值,递归
    public static int addn(int n) {
        if (n == 1) {
            return n;
        }else {
            return n + addn(n - 1);
        }
    }

    //消除递归,依靠栈来消除
    public static int addn1(int n) {
        Stack<Params> stack = new Stack<>();
        int currentReturnValue = 0;
        int currentReturnAddress = 1;
        Params params = null;

        boolean flag = true;
        while (flag ) {
            switch (currentReturnAddress) {
                //初始的参数封装为Params对象,压入栈,设置一下走的分支地址是第二分支
                case 1:
                    params = new Params(n, 6);
                    stack.push(params);
                    currentReturnAddress = 2;
                    break;
                //模拟递归算法的边界条件,满足边界条件,把值赋给currentReturnValur,设定下一跳为5,否则设定下一条为3
                case 2:
                    params = stack.peek();
                    if (params.getN() == 1) {
                        currentReturnValue = params.getN();
                        currentReturnAddress = 5;
                    }else {
                        currentReturnAddress = 3;
                    }
                    break;
                 //模拟递归,n-1作为新的参数压入栈,参数对象返回地址4,设置下一跳:2
                case 3:
                    params = stack.peek();
                    params = new Params(params.getN()-1,4);
                    stack.push(params);
                    currentReturnAddress = 2;
                    break;
                //将栈中的参数对象取出,将要获得的值做叠加操作,跳转步骤5
                case 4:
                    params = stack.peek();
                    currentReturnValue += params.getN();
                    currentReturnAddress = 5;
                    break;
                //把前面第四分支已经叠加过的参数,从栈中删除,如果栈中的参数删除完了,根据参数对象的返回地址,设定下一跳地址
                case 5:
                    params = stack.pop();
                    currentReturnAddress = params.getReturnAddress();
                    break;
                 //完成运算,结束while循环,等同于递归完毕
                case 6:
                    flag = false;
            }

        }
        return currentReturnValue;
    }
}

//写一个封装参数的类
class Params{
    private int n;
    private int returnAddress;  //返回地址

    public Params(int n, int address) {
        this.n = n;
        this.returnAddress = address;
    }

    public void setN(int n) {
        this.n = n;
    }

    public void setReturnAddress(int returnAddress) {
        this.returnAddress = returnAddress;
    }

    public int getN() {
        return n;
    }

    public int getReturnAddress() {
        return returnAddress;
    }
}

八、求一个数的乘方

package recursion;

/**
 * 计算一个数的乘方
 */
public class RecursionTest8 {
    public static void main(String[] args) {
        System.out.println(pow(2,6));
    }

    //递归方法
    public static int pow(int x, int y) {
        if (y == 0) {
            return 1;
        }
        if (y == 1) {
            return x;
        }
        if (y % 2 == 1) {
            return pow(x * x,y/2) * x;
        }else {
            return pow(x * x, y / 2);
        }
    }
}

九、背包问题

package recursion;

public class RecursionTest9 {
    public static void main(String[] args) {
        int[] arr = new int[]{11, 8, 7, 6, 5};
        Knapsack knapsack = new Knapsack(arr);
        knapsack.doKnapsack(22,0);
    }
}

//解决背包问题的类
class Knapsack{
    private int[] data;  //用来被选择的数据项组成的数组
    private boolean[] selects;  //这个数组和上面的数组的长度是一样的,true表示被选中

    //初始化上面的属性
    public Knapsack(int[] data) {
        this.data = data;
        selects = new boolean[data.length];
    }

    //解决背包问题的方法
    public void doKnapsack(int aim, int index) {
        //边界条件
        if (aim != 0 && index >= data.length) {
            return;  //所有的组合都测试了,没有找到
        }

        if (aim == 0) { //找到了
            for (int i = 0; i < selects.length; i++) {
                if (selects[i]) {
                    System.out.print(data[i] + "  ");
                }
            }
            System.out.println();
            return;
        }

        selects[index] = true;
        doKnapsack(aim-data[index],index+1);
        selects[index] = false;
        doKnapsack(aim,index+1); //上面的数据放进背包里对应的所有的组合都不对,从下一个数据项重来
    }
}

十、组合问题

package recursion;

public class RecursionTest10 {
    public static void main(String[] args) {
        char[] arr = new char[]{'A', 'B', 'C', 'D', 'E'};
        Comb comb = new Comb(arr);
        comb.doComb(3,0);
    }
}

class Comb{
    private char[] persons;
    private boolean[] selects;

    public Comb(char[] data) {
        this.persons = data;
        selects = new boolean[data.length];
    }

    //具体实现组合的递归方法
    public void doComb(int selectNum, int index) {
        //边界
        if (selectNum == 0) { //找到
            for (int i = 0; i < selects.length; i++) {
                if (selects[i]) {
                    System.out.print(persons[i] + "  ");
                }
            }
            System.out.println();
            return;
        }

        if (index >= persons.length) {  //所有的组合都找完了
            return;
        }

        selects[index] = true;
        doComb(selectNum - 1, index + 1);
        selects[index] = false;
        doComb(selectNum,index+1);
    }
}

当发现递归的效率比较低时,我们可以尝试用循环或者栈来代替它

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值