如何跟踪递归函数

时间:2020-02-07 03:09:04

标签: c++

因此,在我的一堂课上,我正在学习递归,我试图找出一个问题,但是找不到正确的答案。

我一直得到11,但正确的答案是6。有人可以帮助我获得更好的理解,并希望解释一下如何跟踪代码。谢谢。

我现在的追踪方式:

int f(int x, int y) {
  if (x <= 0) {
     return y;
  }
  return f(x - 1, y + 1) - f(x / 2, y * 2);
}

What is f(4, -1)?
f(4,-1)
return   f(3,0) - f(2,-2)
return   f(2,1) - f(1,-4)
return   f(1,2) - f(0,-8)
return   f(0,3) - (-8)
return   3 + 8  = 11.

3 个答案:

答案 0 :(得分:4)

您没有考虑到对 <script src="https://www.gstatic.com/firebasejs/7.8.0/firebase-admin.js"></script> 的呼叫中的大部分正在对f()进行 2 内部呼叫。因此,真正的痕迹将更像以下那样分解。真正的答案是f(),而不是您的教授告诉您的2

6

Live Demo

答案 1 :(得分:1)

这是具有递归调用控制流的ASCII艺术,

f(4,-1)-------->+
    .   //f(4 - 1, -1 + 1)
    .         f(3,0)------->+
    .           .           |
    .           .     //f(3-1,0+1)          
    .           .         f(2,1)----------->+
    .           .           .               |
    .           .           .      // f(2-1,1+1)    
    .           .           .           f(1,2)--------->+
    .           .           .               .           |
    .           .           .               .   //f(1-1,2+1)
    .           .           .               .       f(0,3)--------->+
    .           .           .               .           .       //as (x == 0) return 3
    .           .           .               .           .           |
    .           .           .               .           |<----(3)---+
    .           .           .               .           |
    .           .           .               .   //f(1/2,2*2)
    .           .           .               .       f(0,4)--------->+
    .           .           .               .           .       //as (x == 0) return 4
    .           .           .               .           .           |
    .           .           .               .           +<----(4)---+
    .           .           .               .           |
    .           .           .               .   //f(1-1,2+1) - f(1/2,2*2) = 3 - 4 = -1 
    .           .           .               +<---(-1)---+
    .           .           .               |
    .           .           .       // f(2/2,1*2)
    .           .           .           f(1,2)--------->+
    .           .           .               .           |
    .           .           .               .   //f(1-1,2+1)
    .           .           .               .       f(0,3)--------->+
    .           .           .               .           .    //as (x == 0) return 3
    .           .           .               .           .           |
    .           .           .               .           +<----(3)---+
    .           .           .               .           |
    .           .           .               .   //f(1/2,2*2)
    .           .           .               .       f(0,4)--------->+
    .           .           .               .           .   //as (x == 0) return 4
    .           .           .               .           .           |
    .           .           .               .           +<----(4)---+
    .           .           .               .           |
    .           .           .               .    //f(1-1,2+1) - f(1/2,2*2) = 3 - 4 = -1
    .           .           .               +<---(-1)---+
    .           .           +<----(0)-------+
    .           .           |
    .           .     //f(3/2,0*2)  
    .           .         f(1,0)----------->+
    .           .           .               |
    .           .           .       //f(1-1,0+1)
    .           .           .           f(0,1)--------->+
    .           .           .               .     //as (x == 0) return 1
    .           .           .               .           |
    .           .           .               +<----(1)---+
    .           .           .               |
    .           .           .       //f(1/2,0*2)
    .           .           .           f(0,0)--------->+
    .           .           .               .     //as (x == 0) return 0
    .           .           .               .           |
    .           .           .               +<----(0)---+
    .           .           .               |
    .           .           .       //f(0,1)-f(0,0) = 1- 0 = 0
    .           .           +<-----(1)------+
    .           .           |
    .           .   // f(3-1,0+1) - f(3/2,0*) = 0 - 1 = -1   
    .           +<----(-1)--+
    .           |
    .    //f(4/2,-1*2)
    .        f(2,-2)------->+
    .           .           |
    .           .       //f(2-1,-2+1)
    .           .         f(1,-1)---------->+
    .           .           .               |
    .           .           .       //f(2-1,-2+1)
    .           .           .           f(0,0)--------->+
    .           .           .               .   //as (x == 0) return 0
    .           .           .               .           |
    .           .           .               +<----(0)---+
    .           .           .               |
    .           .           .       //f(1/2,-1*2)
    .           .           .           f(0,-2)-------->+
    .           .           .               .   //as (x == 0) return -2
    .           .           .               .           |
    .           .           .               +<---(-2)---+
    .           .           .               |
    .           .           .       //f(0,0)-f(0,-2) = 0 - (-2) = 2
    .           .           +<----(2)-------+
    .           .           |
    .           .       //f(2/2,-2*2)
    .           .         f(1,-4)---------->+
    .           .           .               |
    .           .           .           f(0,-3)-------->+
    .           .           .               .   //as (x == 0) return -3
    .           .           .               .           |
    .           .           .               +<---(-3)---+
    .           .           .               |
    .           .           .           f(0,-8)-------->+
    .           .           .               .    //as (x == 0) return -8
    .           .           .               .           |
    .           .           .               +<---(-8)---+
    .           .           .               |
    .           .           .       //f(0,-3) -f(0,-8) = -3 -(-8) = 5
    .           .           +<-----(5)------+
    .           .           |
    .           .   //f(1,-1)-f(1,-4) = 2 - 5 = -3
    .           +<----(-3)--+
    .           |
    .   //f(4 - 1, -1 + 1) - f(4/2,-1*2) = -1 - (-3) = 2
    <----(2)----+

如何理解,

  1. 每列代表一个函数调用,该函数调用随后进行2次递归调用。
  2. <--(x)---代表返回值x

调用函数f(x,y)时,将对f(x-1,y + 1)进行递归调用,直到x为零为止,然后递归调用f(x / 2,y * 2)。< / p>

请考虑以下情况,使用f(1,2)调用对f(0,3)和f(0,4)进行两次后续递归调用,并将两者的返回值作为f(1,2)的返回值进行计算)

f(1,2)--------->+
    .           |
    .   //f(1-1,2+1)
    .       f(0,3)--------->+
    .           .       //as (x == 0) return 3
    .           .           |
    .           |<----(3)---+
    .           |
    .   //f(1/2,2*2)
    .       f(0,4)--------->+
    .           .       //as (x == 0) return 3
    .           .           |
    .           +<----(4)---+
    .           |
    .   //f(1-1,2+1) - f(1/2,2*2) = 3 - 4 = -1 
    +<---(-1)---+

让我尝试用不同的方式来表达它, enter image description here

答案 2 :(得分:0)

如果需要,可以手动打印出迹线。在大多数情况下,它可能不如调试器好,但有时会派上用场。 https://godbolt.org/z/WpSYNj

#include <iostream>

int g_tabs = 0;
struct trace
{
  trace(int x, int y)
  { 
    for(int i = 0; i < g_tabs; ++i)
      std::cout << "  "; 
    std::cout << "f(" << x << ", " << y << ") {\n";
    ++g_tabs;
  }
  ~trace() 
  {
    --g_tabs;
    for(int i = 0; i < g_tabs; ++i)
      std::cout << "  "; 
    std::cout << "}\n";
  }
};
void print(int res)
{
    for(int i = 0; i < g_tabs; ++i)
      std::cout << "  "; 
    std::cout << "result[ " << res << " ]\n";
}
void print(int l, int r, int res)
{
    for(int i = 0; i < g_tabs; ++i)
      std::cout << "  "; 
    std::cout << "result[ " << res << " ] = " << l << " - " << r << '\n';
}

int f(int x, int y)
{
  trace t(x, y);
  if (x <= 0) {
     print(y);
     return y;
  }
  int left = f(x - 1, y + 1);
  int right = f(x / 2, y * 2);
  int result = left - right;
  print(left, right, result);
  return result;
}

int main()
{
    f(5, 3);
    return 0;
}