对C ++中的基本递归感到困惑

时间:2017-10-14 20:01:53

标签: c++ recursion

void print(int p)
{
    if (p==0)
    {
       return;
    }

    print(p-1);
    cout<<p;
    return;
}

这是一个基本功能,可根据您输入的数字计算,因此如果您发送6,则打印123456.

我一直盯着这看半个小时,我无法弄清楚它是如何运作的。为什么递归调用print(p-1);只是导致语句if(p==0)并且在到达cout<<p之前返回?

cout<<p如何访问?我完全理解在递归调用之前放置cout<<p;时它是如何工作的,而是像654321那样打印。

4 个答案:

答案 0 :(得分:4)

您似乎认为return总是返回到main(或者您调用print的地方),和/或递归调用替换自身。这不是真的。

如果您致电print(6),则会以if开头,然后继续print(p-1);。此时,print(5)的调用已启动,但stil之前存在print(6)并等待print(5)完成。

print(5)正在执行相同操作,导致调用print(4)print(5)等待print(4)。等等...

在某些时候,print(1)会调用print(0),而if会在调用另一个print之前立即结束该功能。现在,当print(0)结束时,print(1)会继续使用其代码,即cout。在此之后,print(1)结束,导致print(2)继续其工作,依此类推......

最后,当print(5)结束时,最顶层的嵌套调用(print(6))会继续,并且在cout之后,它可以返回到main(或从哪里)否则它被称为。)

答案 1 :(得分:3)

递归调用就像stack一样。如果我们尝试通过将您的调用扩展为print并将p替换为其值来实现可视化,我们会得到以下内容:

print(4)
{
    if (4==0)
        return;
    print(3)
    {
        if (3==0)
            return;
        print(2)
        {
            if (2==0)
                return;
            print(1)
            {
                if (1==0)
                    return;
                print(0)
                {
                    if (0==0)
                        return;  // This return is called
                    print(-1)    // Line skipped
                    cout<<0;     // Line skipped
                    return;      // Line skipped
                }
                cout<<1;
                return;
            }
            cout<<2;
            return;
        }
        cout<<3;
        return;
    }
    cout<<4;
    return;
}

请注意,return语句只保留当前版本的print,这是堆栈中的当前函数。这意味着我们最终会一直走回创建的堆栈。

答案 2 :(得分:1)

虽然还有其他答案并且它们都是正确的,但我会尝试解释一些其他问题。在C ++中使用这种类型的递归仅用于学术目的,但是像LISP这样的语言没有循环并依赖于递归。

在递归函数中,需要考虑三个关键要素:

  1. 必须有一个条件,当遇到结束递归。
  2. 函数调用自身的函数中必须有一个点(可能不止一个)。当它这样做时,调用应该“更接近” end 条件。例如,倒计时,调用会减少参数。
  3. 当函数在整个过程中执行某些操作时,可能会在调用递归之前或之后执行该操作。根据调用的完成方式,我们得到一个递归策略或另一个。您可能听说过深度优先搜索广度优先搜索
  4. 例如。如果你这样做:

    if(p<=0)
      return;
    
    print(p-1);
    cout << p;
    

    您的打印顺序与以下相反:

    if(p<=0)
      return;
    
    cout << p;
    print(p-1);
    

    如果您首先递归然后再打印,那么您使用的是深度优先策略。递归将继续,直到满足 end 条件,然后将完成打印。所以第一次打印将是更接近 end 条件的打印;然后是下一个;等等。你可以弄清楚在另一种情况下会发生什么。

    值得注意的是,每次递归时,某种堆栈(顺便说一下,以LIFO顺序工作)都必须保持所有先前递归的状态。当您的问题需要大量递归时,您最终可能会使用所有可用资源。因此,在像C ++这样的语言中,最好使用一个只保留一个 state 的循环。

    然而,当您必须解决某些问题时,递归会很方便。我想到的是解析表达式,其中某些位具有与某些位不同的优先级。像1+2*3一样。在这种情况下,应首先评估2*3,然后将结果添加1+6以产生7。这称为递归下降解析器

答案 3 :(得分:0)

想想print(1):它传递if语句,然后调用print(0);返回时,通过调用print(1)继续调用cout