为啥这个递归函数超过调用堆栈大小?

Posted

技术标签:

【中文标题】为啥这个递归函数超过调用堆栈大小?【英文标题】:Why is this recursive function exceeding call stack size?为什么这个递归函数超过调用堆栈大小? 【发布时间】:2018-10-28 16:29:38 【问题描述】:

我正在尝试编写一个函数来找到 1 到 20 之间的所有整数除以的最小数字。 (我们称之为条件 D)

这是我的解决方案,它以某种方式超出了调用堆栈大小限制。

function findSmallest(num)
    var count = 2
    while (count<21)
        count++
        if (num % count !== 0)
            // exit the loop
            return findSmallest(num++)
        

    
    return num


console.log(findSmallest(20))

我对此的推理有问题,但这是我的看法(请纠正我的错误):

使用不满足条件 D 的数 N 调用此函数将导致再次使用 N + 1 调用该函数。最终,当它达到应满足条件 D 的数 M 时,while 循环将运行所有方法通过并且函数返回数字 M 并且不再有递归调用。

但我在运行时收到此错误:

函数 findSmallest(num) ^

RangeError: 超出最大调用堆栈大小

我知道这样的错误几乎总是由于递归函数没有达到基本情况。这是这里的问题吗?如果是,问题出在哪里?

【问题讨论】:

【参考方案1】:

您的问题是您输入了超过 2 亿次递归(加上上一个答案中发现的错误)。您要查找的数字是所有素数的倍数乘以它们在定义范围的每个数字中的最大出现次数。所以这是你的解决方案:

function findSmallestDivisible(n) 
    if(n < 2 || n > 100) 
    throw "Numbers between 2 and 100 please";
  
    var arr = new Array(n), res = 2;
  arr[0] = 1;
  arr[1] = 2;
  for(var i = 2; i < arr.length; i++) 
    arr[i] = fix(i, arr);
    res *= arr[i];
  
  return res;


function fix(idx, arr) 
    var res = idx + 1;
  for(var i = 1; i < idx; i++) 
    if((res % arr[i]) == 0) 
        res /= arr[i];
    
  
  return res;

https://jsfiddle.net/7ewkeamL/

【讨论】:

【参考方案2】:

我发现了两个错误。

在您的 while 循环中,count 的值是 3 到 21。 num 的值在循环中更改。 num++ 应该是 num + 1

但是,即使修复了这些错误,也无法解决错误。 答案是232792560。 这个递归深度太大,堆栈内存耗尽。

例如,此代码会导致相同的错误。

function foo (num) 
    if (num === 0) return
    else foo(num - 1)


foo(232792560)

没有递归的编码可以避免错误。

【讨论】:

以上是关于为啥这个递归函数超过调用堆栈大小?的主要内容,如果未能解决你的问题,请参考以下文章

为啥每次递归都使用这么多的堆栈空间?

Python递归限制与堆栈大小?

为啥 malloc() 和普通数组声明分配的堆栈帧大小不同?

Maximum call stack size exceeded

cudaErrorIllegalInstruction 递归函数调用

函数递归调用过程中的调用堆栈的情况