循环和递归对比

循环与递归对比

大学学习递归的时候有一句话印象深刻:所有的递归都可以改写为循环。这句话我是同意的,因为递归其实本质上就是栈的操作。虽然如此,但递归有递归的优点,递归算法写出来的程序都比较简短而且优雅,缺点是其站在了计算机的角度,人很难深究其中,容易陷入递归的汪洋大海中。既然所有的递归都可以改写为循环,反之,那循环是否可以改写为递归呢?

今天再次想到这个问题,是因为做了《剑指Offer》的一道递归题:合并两个排序的链表,牛客网剑指offer第16道题

递归和循环相同点

递归和循环都有退出条件,每次递归或循环执行的程序体都是一样的。while (true)循环和递归最相似,两者思路都很清晰,所以我比较喜欢while (true)循环

// 递归写法
public void recursive(int n) {
    // 递归结束条件
    if (n == 0) {
        return;
    }

    // 其他子问题,递归解决
    recursive(n - 1);
}


public void theLoop() {

    // 循环写法
    while (true) {
        // 循环结束条件
        if (n == 0) {
            break;
        }

        // 其他问题继续循环
        n = n - 1;
    }
}

递归种类

我大致将递归分为两种:可以有返回值和无返回值,这两个貌似差别挺大,但目前我想不明白。比如这道题,打印从1加到n的和。无返回值的话写起来比较麻烦。

实现如下:

/**
 * 自我思考,1加到n无返回值和有返回值两种
 */

 public class Sum {

    public static void main(String[] args){
        System.out.println(recursiveReturnInt(5));
        recursiveReturnVoid(5, 0);
    }

    // 有返回值的递归写法
    public static int recursiveReturnInt(int n){
        if (n == 0) {
            return 0;
        }
        return n + recursiveReturnInt(n - 1);
    }

    // 无返回值的递归写法
    public static void recursiveReturnVoid(int n, int sum){

        if (n == 0) {
            System.out.println(sum);
            return;
        }
        sum += n;
        recursiveReturnVoid(n - 1, sum);
        
    }
 }

循环是否都可以改为递归

应该是不可以的,不过解决子问题的循环都可以改为递归。如冒泡排序,反转链表等。冒泡排序n个数时每次都把最大的数排到最后一位,接着排序剩下的n-1位。反转链表每次都反转当前节点和下一个节点,接着指针前进反转下一个节点和下下个节点。

以下是冒泡排序的非递归和递归写法。

/**
 * 自我思考,冒泡排序的递归和非递归写法
 */

 public class BubbleSortTwoSolution {

    public static void main(String[] args) {

        int[] array = new int[]{4, 6, 1, 3, 2, 3, 9, 8, 0};
        bubbleSortLoopSolution(array);
        System.out.print("循环写法:");
        for(int i : array) {
            System.out.print(i + " ");
        }
        System.out.println();

        array = new int[]{4, 6, 1, 3, 2, 3, 9, 8, 0};
        bubbleSortRecursiveSolution(array, 8);
        System.out.print("递归写法:");
        for(int i : array) {
            System.out.print(i + " ");
        }
        System.out.println();

        array = new int[]{4, 6, 1, 3, 2, 3, 9, 8, 0};
        bubbleSortWhileLoopSolution(array);
        System.out.print("while (true)写法:");
        for(int i : array) {
            System.out.print(i + " ");
        }
        System.out.println();
    }

    // 冒泡排序循环写法
    public static void bubbleSortLoopSolution(int[] array) {

        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j] > array[j+1]) {
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                }
            }
        }
    }

    // 冒泡排序递归写法
    public static void bubbleSortRecursiveSolution(int[] array, int index) {

        if (index < 0) {
            return;
        }

        for (int j = 0; j < index; j++) {
            if (array[j] > array[j+1]) {
                int tmp = array[j];
                array[j] = array[j+1];
                array[j+1] = tmp;
            }
        }

        bubbleSortRecursiveSolution(array, index-1);
    }

    // while (true)循环写法,跟递归很像
    public static void bubbleSortWhileLoopSolution(int array[]) {

        int index = array.length - 1;
        while (true) {

            if (index < 0) {
                break;
            }

            for (int j = 0; j < index; j++) {
                if (array[j] > array[j+1]) {
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                }
            }

            index--;
        }
    }
 }

从上面可以看出来,递归和while(true)循环很像,并且思路很清晰。用递归来解决存在子问题的算法,代码很优雅。

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦