递归与堆栈实现。为什么递归返回 StackOverflow 而 Stack 不返回?

2022-09-04 07:22:53

这个问题的依据:

我今年夏天将以CS学位毕业,没有一次我有一个教授强调Stack的重要性。但是,我有多个项目都专注于递归的使用。我发现递归有用且令人兴奋,我在我的个人项目中经常使用它。

我最近参加了一次求职面试,面试官对问题的递归解决方案感到非常失望。他们想要堆栈解决方案。我做了一堆研究,但我仍然不确定何时使用哪个。

给出以下演示:

public class TestCode {

    static long startTime = 0;
    static long stopTime = 0;
    static long totalTime = 0;

    public static void main(String[] args) throws IOException {
        int x = 10000;
        startTime = System.currentTimeMillis();
        recursiveMethod(x);
        System.out.println();
        stopTime = System.currentTimeMillis();
        totalTime = stopTime - startTime;
        System.out.println(totalTime);
        System.out.println();

        startTime = System.currentTimeMillis();
        stackMethod(x);
        System.out.println();
        stopTime = System.currentTimeMillis();
        totalTime = stopTime - startTime;
        System.out.println(totalTime);
        }

    public static void recursiveMethod(int a){
        if(a >= 0){
            recursiveMethod(a - 1);
            System.out.println("Recursion: " + a + " ");
        }
    }

    public static void stackMethod(int a){
        Stack<Integer> myStack = new Stack<Integer>();
        while(a >= 0){
            myStack.push(a);
            a--;
        }
        while(myStack.isEmpty() == false){
            a = myStack.pop();
            System.out.println("Stack: " + a + " ");
        }
    }
}

两种解决方案在大约200 ms内完成。通过添加零来更改 的值:给我一个StackOverflowError(在递归方法上)。xx = 100000

当我注释掉具有相同值的程序的递归解决方案时,成功运行,这意味着Stack解决方案的工作远远超出了递归解决方案的限制。x

问题

  • 为什么递归解决方案生成的 StackOverflowError 具有与 Stack 解决方案相同的迭代次数,而 Stack 解决方案没有出错?
  • 如果 Stack 解决方案功能更强大且使用的内存更少,您何时会使用递归解决方案?
  • 递归和堆栈/迭代解决方案之间的根本区别是什么,在选择一个之前必须考虑一个?

答案 1

为什么递归解决方案生成的 StackOverflowError 具有与 Stack 解决方案相同的迭代次数,而 Stack 解决方案没有出错?

递归使用线程堆栈,并且具有更低的限制。STack使用堆,这要大得多,但它最终会超出内存错误。

如果 Stack 解决方案功能更强大且使用的内存更少,您何时会使用递归解决方案?

它的速度要慢得多,编写起来更难,更容易出错,并且会占用更多的内存。只是限制要高得多。

我看到很多人在Stacks上使用递归,这是因为递归“更容易”,尽管效率要低得多?(3 行代码与本示例中的 7 行代码相比)。

您还没有预热代码来说明哪个更有效。我会忽略前 10,000 次迭代或运行时间的第一秒。

虽然我知道你不能说为什么其他人都使用递归,

通常,递归的效率低于使用迭代,但是有些问题不能轻易地重构为使用递归。95%的问题在Java中使用迭代的效率要高得多。

我想质疑它的用途而不是使用它,因为如果没有充分的理由,“其他人都会这样做”。

大多数时候,人们使用递归是因为它更简单,更快,但它可能会耗尽堆栈空间,并且在极少数情况下,您必须使用堆栈或数组列表,这比堆栈更有效。


答案 2

大多数机器体系结构使用固定大小的堆栈,因此递归算法的工作内存量有限。但是,您分配的显式堆栈可以增长到主内存的大小。因此,它有更多的工作空间。再加上递归堆栈每帧必须包含比显式堆栈更多的数据,你可以看到为什么堆栈实现更有效。

递归算法通常看起来更优雅;但是由于这些原因,基于堆栈的算法通常是更好的选择。只有当递归级别的数量严格限定时,才应考虑递归算法。


推荐