Рекурсивные функции в C/C++

Если мы рассматриваем рекурсивную функцию в C/C++, действительно ли они полезны всегда? Где точно они используются главным образом? Есть ли какие-либо преимущества с точки зрения памяти при помощи рекурсивных функций?

Править: рекурсия лучше или использующий некоторое время цикл?

5
задан Vijay 16 February 2010 в 15:51
поделиться

10 ответов

Попробуйте:

$this->load->database();
echo $this->db->dbprefix;

Обычно вы можете использовать $ this- > config- > предмет но я думаю, что это позволяет только переменные, набор в $ config

-121--3232461-

Это, конечно, зависит от того, что делает ваша конкретная среда при загрузке программы; куда помещаются статические данные программы? Во многих операционных системах программа загружается в кучную память и запускается оттуда, так что ваши статические данные все равно окажутся в куче.

-121--4950472-

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

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

10
ответ дан 18 December 2019 в 06:11
поделиться

проверьте состояние порта 5900

-121--2801443-

Ознакомьтесь с подробным сравнением элементов управления Telerik для Silverlight и набора инструментов Silverlight.

http://www.telerik.com/products/silverlight/resources/radcontrols-versus-toolkit-comparison.aspx

-121--3505042-

При использовании рекурсии можно сохранить данные в стеке (фактически в контекстах вызова всех функций над текущим экземпляром), которые необходимо было бы сохранить в куче с динамическим распределением, если бы вы пытались сделать то же самое с помощью цикла while . Подумайте о большинстве алгоритмов «разделяй и побеждай», где есть две вещи, которые нужно сделать для каждого вызова (то есть один из вызовов не является хвостовым рекурсивным).

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

1
ответ дан 18 December 2019 в 06:11
поделиться

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

4
ответ дан 18 December 2019 в 06:11
поделиться

Рекурсивные функции упрощают кодирование решений, имеющих рекуррентное отношение .

Например, функция факториала имеет рекуррентное отношение:

 factorial(0) = 1
 factorial(n) = n * factorial(n-1)

Ниже я реализовал факториал, используя рекурсию и цикл.

Рекурсивная версия и отношение рекуррентности, определенные выше, выглядят одинаково и поэтому их легче читать.

Рекурсивный:

double factorial ( int n )
{
 return ( n ? n * factorial ( n-1 ) : 1 );
}

Цикл:

double factorial ( int n )
{
 double result = 1;
 while ( n > 1 )
 {
  result = result * n;
  n--;
 }
 return result;
}

Еще одна вещь:

Рекурсивная версия факториала включает хвостовой вызов самого себя и может быть оптимизирована по хвостовому вызову. Это сводит пространственную сложность рекурсивного факториала к пространственной сложности итеративного факториала.

0
ответ дан 18 December 2019 в 06:11
поделиться

Используйте:

FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized;

. После этого форма помещается на панель задач.

-121--949009-

Можно использовать netstat для проверки наличия установленного подключения к порту, который прослушивает сервер VNC.

попробуйте netstat -an | найти «ESTABLISHED» | найти «: 5900» в Windows в командной строке.

Если кто-то подключен, для него появится запись строки.

Примечание. Если вы подключаетесь к другому серверу, то этот поиск также обнаружит это подключение, поэтому обратите внимание на наличие : 5900 во втором столбце слева, так как это локальный компьютер.

-121--2801444-

Есть две причины, которые я вижу для использования рекурсии:

  • алгоритм работает на рекурсивных структурах данных (например, дерево)
  • Алгоритм имеет рекурсивный характер (часто бывает для математических задач, так как рекурсия часто предлагает красивые решения)

Обрабатывать рекурсию с осторожностью, так как всегда существует опасность бесконечной рекурсии.

0
ответ дан 18 December 2019 в 06:11
поделиться

Внедрите QuickSort с рекурсией и без нее, тогда вы сможете сами определить, полезно это или нет.

3
ответ дан 18 December 2019 в 06:11
поделиться

Я часто найти рекурсивные алгоритмы легче для понимания, потому что они включают менее изменчивое состояние. Рассмотрим алгоритм определения наибольшего общего делителя двух чисел.

unsigned greatest_common_divisor_iter(unsigned x, unsigned y)
{
    while (y != 0)
    {
        unsigned temp = x % y;
        x = y;
        y = temp;
    }
    return x;
}

unsigned greatest_common_divisor(unsigned x, unsigned y)
{
    return y == 0 ? x : greatest_common_divisor(y, x % y);
}

На мой вкус, в итеративной версии происходит слишком много переименований. В рекурсивной версии все неизменяемо, поэтому вы даже можете сделать x и y const , если хотите.

2
ответ дан 18 December 2019 в 06:11
поделиться

Рекурсия определенно имеет преимущества при задачах с рекурсивной природой. Другие плакаты называли некоторых из них.

Однозначное использование возможностей C для рекурсии имеет преимущества в управлении памятью. Когда вы пытаетесь избежать рекурсии, большую часть времени для решения проблемы используется собственный стек или другой динамический тип данных. Это включает управление динамической памятью в C / C ++. Динамическое управление памятью дорого и подвержено ошибкам!

Вы не можете превзойти стек

С другой стороны, когда вы просто используете стек и используете рекурсию с локальными переменными - управление памятью просто, а стек в большинстве случаев более эффективен по времени затем все управление памятью вы можете сделать самостоятельно или с помощью простого управления памятью C / C ++. Причина в том, что системный стек представляет собой такую ​​простую и удобную структуру данных с низкими накладными расходами и реализуется с использованием специальных операций процессора, оптимизированных для этой работы. Поверьте, вы не сможете превзойти это, поскольку компиляторы, операционные системы и процессоры оптимизированы для манипуляций со стеком на протяжении десятилетий!

PS: Также стек не становится фрагментированным, в отличие от кучи памяти. Таким образом также можно сэкономить память, используя стек / рекурсию.

4
ответ дан 18 December 2019 в 06:11
поделиться

Этот трюк по вызову частных методов с помощью Delegate.CreateDelegate чрезвычайно аккуратен.

var subject = new Subject();
var doSomething = (Func<String, String>)
    Delegate.CreateDelegate(typeof(Func<String, String>), subject, "DoSomething");
Console.WriteLine(doSomething("Hello Freggles"));

Вот контекст, где это полезно

-121--1749454-

Это работает:

map.resource :post, :collection => { :my_action => :get}
-121--128791-

Динамическое программирование - это ключевая область, где рекурсия имеет решающее значение, хотя она выходит за рамки этого (запоминание дополнительных ответов может дать резкие улучшения производительности). Алгоритмы - это те, где обычно используется рекурсия, а не обычное кодирование день в день. Это скорее компьютерная научная концепция, чем программная.

1
ответ дан 18 December 2019 в 06:11
поделиться

Стоит упомянуть, что на большинстве функциональных языков (например, на схеме) вы можете воспользоваться преимуществами оптимизации хвостового вызова и, таким образом, вы можете использовать рекурсивные функции без увеличения объем памяти в вашем стеке.

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

1
ответ дан 18 December 2019 в 06:11
поделиться