Как найти глубину рекурсивной функции в C++

Как я могу найти текущую глубину внутри рекурсивной функции в C++ без прохождения предыдущего уровня? т. е. Можно ли узнать, сколько раз вызывалась функция без использования параметра для отслеживания уровня и передачи этого числа в качестве параметра каждый раз, когда вызывается функция?

моя рекурсивная функция выглядит так:
DoSomething(int level)
{
  print level;
  if (level > 10)
    return;
  DoSomething(++level);
}

main
{
  DoSomething(0);
}

7 ответов


основываясь на ответе, уже данном JoshD:

void recursive() 
{ 
    static int calls = 0;
    static int max_calls = 0;
    calls++;
    if (calls > max_calls)
        max_calls = calls;

    recursive();

    calls--;
}

это сбрасывает счетчик после завершения рекурсивной функции, но по-прежнему отслеживает максимальную глубину рекурсии.

Я бы не использовал статические переменные, подобные этому, ни для чего, кроме быстрого теста, который будет удален вскоре после этого. Если вам действительно нужно отслеживать это на постоянной основе, есть лучшие методы.


вы можете использовать статическую переменную в функции...

void recursive()
{
 static int calls = 0;
 calls++;
 recursive();
}

конечно, это будет продолжать подсчет при запуске нового исходного вызова....


Вы можете использовать локальную статическую переменную, если вы не заботиться о потокобезопасности.

хотя это даст вам правильный подсчет только при первом запуске рекурсивной процедуры. Лучшим методом будет класс типа RAII guard, который содержит внутреннюю статическую переменную. В начале рекурсивной процедуры создайте класс guard. Конструктор увеличит внутреннюю статическую переменную,а деструктор уменьшит ее. Таким образом, когда вы создаете новый stack-frame счетчик увеличивается на единицу, и когда вы возвращаетесь из каждого стека-кадра, счетчик будет уменьшаться на единицу.

struct recursion_guard
{
    recursion_guard() { ++counter; }

    ~recursion_guard() { --counter; }

    static int counter;
};

int recursion_guard::counter = 0;

void recurse(int x)
{
    recursion_guard rg;
    if (x > 10) return;
    recurse(x + 1);
}

int main()
{
    recurse(0);
    recurse(0);
}

обратите внимание, однако, что это все еще не потокобезопасно. Если вам нужна потокобезопасность, вы можете заменить переменную static-storage переменной thread-local-storage, используя boost::thread_specific_ptr или локальные объекты потока C++0x.


Если вы хотите, чтобы он был повторным и потокобезопасным, почему бы и нет:

void rec(int &level)  // reference to your level var
{
   // do work

   rec(++level); // go down one level
}

main()
{
   //and you call it like
   int level=0;
   rec(level);

   cout<<level<<" levels."<<endl;
}

нет статических/глобальных переменных чтобы испортить резьбу, и вы можете использовать разные переменные для разных рекурсивных цепочек для проблем повторного входа.


вы также можете передать уровень в качестве параметра шаблона, если он может быть определен во время компиляции. Вы также можете использовать объект функции. Это, безусловно, лучший вариант - меньше хлопот, и статических переменных следует избегать везде, где это возможно.

struct DoSomething {
    DoSomething() {
        calls = 0;
    }
    void operator()() {
        std::cout << calls;
        calls++;
        if (calls < 10)
            return operator()();
        return;
    }
    int calls;
};

int main() {
    DoSomething()(); // note the double ().
    std::cin.get();
}

преобразование level к переменной экземпляра нового объекта (обычно шаблона), способной содержать аргументы и (возможно) функцию. затем вы можете повторно использовать интерфейс recursion accumulator.


вы также можете попробовать использовать глобальную переменную для регистрации глубины.

var depth = 0;

DoSomething()
{
  print ++depth;
  if (depth > 10)
    return;
  DoSomething();
}

main
{
  DoSomething(0);
}