【问题标题】:Keep track of how many times a recursive function has been called in C++跟踪在 C++ 中调用递归函数的次数
【发布时间】:2013-05-23 04:58:03
【问题描述】:

我正在尝试开发一个程序,该程序具有一个参数是字符串向量的函数。我想在该函数上使用递归,但每次调用该函数时,我都想更改参数,例如

fun(stringArray[i]) 

其中 i 是函数被调用的次数。

因此,以更简单的方式,如下所示。但是我需要跟踪函数 fun 执行了多少次。

void fun(){
    cout<<hi;
    if(x!=10)
    fun()
}

int main(){

    fun();
}

假设我只想打印 10 次,所以想要一个递增的变量,当达到 10 时,它会停止。那么总的来说,我能做些什么来跟踪它呢?我尝试使用全局变量,但它们似乎不适用于函数。有什么建议吗?

【问题讨论】:

  • 可以添加参数,递归时递增。
  • 我强烈建议你看看我的调查

标签: c++ recursion global-variables


【解决方案1】:

我看到这里很乱,所以我决定把事情清理干净。

解决方案 0:静态变量

考虑对提议的代码稍作修改

#include<iostream>
using namespace std;

void fun()
{
    static int count=1;
    count++;
    cout << "fun() is called " << count << " times" << endl;
    if(count<=10)
    {
            fun();
    }
}

int main()
{
    cout << "first call" << endl;
    fun();
    cout << "second call" << endl;
    fun();
    cout << "third call" << endl;
    fun();
}

导致此输出:

first call
fun() is called 2 times
fun() is called 3 times
fun() is called 4 times
fun() is called 5 times
fun() is called 6 times
fun() is called 7 times
fun() is called 8 times
fun() is called 9 times
fun() is called 10 times
fun() is called 11 times
second call
fun() is called 12 times
third call
fun() is called 13 times

如您所见,使用静态变量可能会导致一些意外行为。

这是一个一次性功能,将来会让你相当头疼。 此外,静态变量的使用导致代码不可读,容易出错

别这样!

解决方案一:按值传递变量

考虑这段代码:

#include <iostream>
using namespace std;

void fun(int i){
    cout<<i<<endl;
    if(i!=3) {
        i++;
        fun(i);
        fun(i);
    }
}

int main(){
    fun(0);
}

这是输出:

0
1
2
3
3
2
3
3
1
2
3
3
2
3
3

如你所见,输出不是函数被调用的次数

解决方案 2:通过引用传递变量

#include <iostream>
using namespace std;

void fun(int& x){
    if(x>=10)
        return;
    ++x;
    cout << x << endl;
    fun(x);
}

void funEntry(){
    int x = 0;
    cout << "Entry point" << endl;
    fun(x);
}

int main(){
    funEntry();
    funEntry();
}

将打印

Entry point
1
2
3
4
5
6
7
8
9
10

这种方法也适用于像这样的一些更奇特的递归模式

#include <iostream>
using namespace std;

void fun(int i, int& x){
    if(i>=4)
        return;
    ++x;
    cout << i << " " << x << endl;
    fun(i+1,x);
    fun(i+2,x);
}

void funEntry(){
    int x = 0;
    cout << "Entry point" << endl;
    fun(0,x);
}

int main(){
    funEntry();
    funEntry();
}

输出:

Entry point
0 1
1 2
2 3
3 4
3 5
2 6
3 7
Entry point
0 1
1 2
2 3
3 4
3 5
2 6
3 7

【讨论】:

  • 非常感谢您提供详细信息!
【解决方案2】:

添加一个static 变量作为计数器。

#include<iostream>
using namespace std;

void fun()
{
    static int count=1;
    count++;
    cout << "fun() is called " << count << " times" << endl;
    if(count<=10)
    {
            fun();
    }
}

int main()
{
    fun();
}

static 变量只初始化一次,并且值将在函数调用中保留。看这个链接http://en.wikipedia.org/wiki/Static_variable

【讨论】:

  • 或许static int count = 0;会更好
  • @EdHeal - 谢谢,将 count 初始化为 1,以便 fun() 将根据需要被调用 10 次 :)
  • 你是如何处理 main 中对 fun() 的多次调用的?
  • 我建议避免使用静态变量并使用引用传递的变量
【解决方案3】:
void fun(int& x){
    if(x>=10)
        return;
    ... Do something
    ++x;
    fun(x);
}

您应该使用对外部变量的引用

如果按值传递计数器,则不能在同一个函数中进行多次调用

【讨论】:

    【解决方案4】:

    在递归函数中使用静态变量。 静态int i = 0; 在函数的开头,说 i++。

    每次调用函数时,这个 i 都会增加。如果 i 的值变为 10,则可以终止。

    【讨论】:

    • 它可以工作,但你必须记住在退出时重置它,并希望该函数不会同时从多个线程调用。
    • 您还可以使用静态标志将位包装在函数内部,该标志表示其中有一个线程。此标志默认为 false。当你进入函数时,你首先执行一个 while(flag) {},然后一旦你通过了 while 循环,你就将标志设置为 true,当你完成函数时,你再次将标志设置为 false。当然,更好的方法是使用像互斥锁这样的内核对象而不是标志,这样你的其他线程就不会白白浪费 CPU 周期。
    【解决方案5】:

    如果你需要让它递归......

    void fun(int i){
    
        cout<<hi;
        if(i!=10) {
            i++;
            fun(i);
        }
    }
    
    int main(){
    
        fun(0);
    }
    

    希望有帮助吗?

    【讨论】:

    • Sanish 的解决方案比我的更优雅。
    【解决方案6】:

    我知道我回答这个问题真的很晚了。但无论如何,我遵循的方法涉及#1 中的指针 概念,以及#2 中的引用传递 概念。我已经针对河内塔问题测试了这个解决方案,在我看来,它几乎适用于所有类型的递归函数。

    实际上,用第一种方法编写的代码最初是用 C 编写的,但出于显而易见的原因,它也可以在 C++ 中运行。

    方法 #1:在 C 中使用 指针

    假设我们用 rf()

    表示递归函数
    1. 必须创建一个名为 invocations 的整数变量,与其他参数(如果存在)一起传递给递归函数。它必须在 main() 或调用函数中创建。将其初始化为 0。
    2. 然后,在递归函数的参数列表中,再添加一个整数指针类型的参数,并在调用函数中,传递给递归函数,这个参数的值作为变量的地址调用。 例如

      void main(){
      
      int invocations=0;
      
      rf(n,&invocations); // address of variable 'invocations' is passed here
      }
      
    3. 然后,在递归函数的声明部分,您添加了一个额外的参数用于计算函数调用,并将其类型声明为 int 指针, 在函数体本身的第一行,通过以下方式将此整数指针指向的值加1,

      void rf(int n, int* invocations){
      
      (*invocations)++;
      
      /* rest of the function logic goes here */
      
      }
      

    请注意,我已将取消引用运算符 (*)、星号放在括号内,以便告诉编译器首先对其求值,就好像我不这样做一样,它右侧的增量运算符将被求值first 在没有括号的情况下(因为 * 和 ++ 具有相同的优先级,如果出现在同一个表达式中,它们将从右到左计算)

    1. 接下来,打印调用变量的值,在所有递归函数调用都在调用函数中结束之后,在我们的例子中,在 main() 中。 像这样,

      void main(){
      ......
      int invocations=0;
      .......
      rf(n, &invocations);
      printf("\nNumber of invocations of rf()=%d\n", invocations);
      }
      

    方法#2:在C++中使用通过引用传递

    以上步骤都是一样的,只是涉及的变化有以下几种,

    1. 将 rf() 声明中的参数类型从 int* 更改为 int&amp;。像 void rf(int n, int* invocations)void rf(int n, int&amp; invocations)

    2. 更改 rf() 调用语句,传递变量值,而不是其地址。(只需删除 &),如 rf(n, &amp;invocations);rf(n, invocations);

    3. invocations 变量的增量语句从 (*invocations)++; 更改为简单的 invocations++ 在 rf() 主体内。

    就是这样。两种解决方案都会产生相同的效果。它们都适用于我的情况。 告诉我解决方案是否在任何步骤都不清楚,或者它在您的情况下是否无效。

    【讨论】:

      猜你喜欢
      • 2020-04-21
      • 1970-01-01
      • 2022-01-24
      • 2021-07-19
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2021-09-02
      • 1970-01-01
      相关资源
      最近更新 更多