可以实现无限递归吗?

问题描述

我知道对于C来说,每次调用递归函数时,至少将堆栈帧和返回地址写入堆栈,但是有一种晦涩的方法来使它不耗尽内存吗?显然,这纯粹是一个假设问题,因为我无法想象它的用例。

解决方法

您可以使用堆栈来模拟递归

与函数调用和静态变量相关的内存部分(在C中用int x;声明)与与动态分配相关的内存部分(在C中使用malloc())是分开的。只有前者(称为“堆栈”)受到限制,并且会导致“堆栈溢出”错误。好吧,当然这并不完全正确。后者被称为“堆”,当然,您的计算机并不是万能的,如果您真正尝试突破其极限,则它会在某个时刻耗尽内存。

您可以使用尾部递归来避免在调用堆栈中添加层

堆栈溢出是由于调用堆栈的大小引起的。想象一下这样的函数:

int f(int n)
{
    int x;
    if (n < 2)
    {
        return 1;
    }
    else
    {
        x = f(n-1);
        return n * x;
    }
}

在对f进行递归调用时,计算机需要注意以下事实:一旦完成递归调用,我们将需要再进行一次乘法运算。注意这一点是通过在“调用堆栈”中添加一层有关变量值以及代码在哪里的信息来实现的。这需要内存,以防在堆栈太大的情况下导致堆栈溢出。

现在与以下代码进行比较:

int f(int n,int acc)
{
    if (n < 2)
    {
        return acc;
    }
    else
    {
        return f(n-1,n * acc);
    }
}

这次,将递归调用直接封装在return中,这意味着在递归调用之后无需进行其他工作。想象一下,您要我工作并向您报告结果;通过进行递归调用,我将一些工作委托给我的朋友;然后,我不再呆在身边等我的朋友向我报告,以便我可以向您报告,而是立即离开并告诉我的朋友直接向您报告。这样可以通过“剪切中间人”来节省内存。

了解更多:

在具有惰性求值的语言中,您可以编写一个看似无限递归的函数,然后仅根据需要求值: