Какова практическая разница между циклом и рекурсией

В настоящее время я работаю в PHP, поэтому этот пример будет в PHP, но вопрос относится к нескольким языкам.

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

Теперь я хотел сказать ему разницу между циклом и рекурсией, но я не мог найти решение, в котором вам нужна рекурсия по нормальному циклу.

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

Пожалуйста, простите меня за любые ошибки кодирования.

Цикл:

printnumbers(1,10);

public function printnumbers($start,$stop)
{
    for($i=$start;$i<=$stop;$i++)
    {
        echo $i;
    }
}

Теперь приведенный выше код просто просто распечатывает номера.

Теперь сделаем это с рекурсией:

printnumbers(1,10);

public function printnumbers($start,$stop)
{
    $i = $start;
    if($i <= $stop)
    {
        echo $i;
        printnumbers($start+1,$stop);
    }
}

Этот метод выше будет делать то же самое, что и цикл, но только с рекурсией.

Может ли кто-нибудь объяснить мне, что в нем используется один из этих методов.

Ответ 1

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

Рекурсии более мощные в том смысле, что для перевода рекурсии в цикл может потребоваться стек, который вы должны манипулировать собой. (Попробуйте пересечь двоичное дерево, используя цикл, и вы почувствуете боль.)

С другой стороны, многие языки (и реализации), например Java, не реализуют хвостовую рекурсию должным образом. Рекурсия хвоста - это когда последнее, что вы делаете в функции, - это называть себя (как в вашем примере). Такая рекурсия не должна потреблять какой-либо стек, но на многих языках, что означает, что вы не всегда можете использовать рекурсию.

Ответ 2

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

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

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

Особенно функциональные языки хороши при обработке "бесконечной" рекурсии. Императивные языки сосредоточены на итерационных циклах.

Ответ 3

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

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

Ответ 4

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

Проблема с изучением рекурсии - это много примеров (например, факториалов) - плохие примеры использования рекурсии.

По возможности, придерживайтесь петли, если вам не нужно делать что-то другое. Хорошим примером использования рекурсии является цикл по каждому node в дереве с несколькими уровнями дочерних узлов.

Ответ 5

Рекурсия немного медленнее (поскольку вызовы функций медленнее, чем установка переменной), и использует больше места для стеков вызовов большинства языков. Если вы попытались printnumbers(1, 1000000000), рекурсивная версия, скорее всего, произвела бы фатальную ошибку PHP или даже ошибку 500.

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

Ответ 6

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

В этом конкретном случае, с концептуальной (а не реалистической) точки зрения, эти два решения полностью эквивалентны.

Ответ 7

Переполнение стека.

И нет, я не имею в виду сайт или что-то еще. Я ЗНАЧУ "переполнение стека".

Ответ 8

По сравнению с циклами вызов функции имеет свои собственные служебные данные, такие как выделение стека и т.д. И в большинстве случаев циклы более понятны, чем их рекурсивные копии.

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

Ответ 9

Вам не нужна рекурсия для такой плоской структуры. В первом коде, который я когда-либо использовал, рекурсия включала управление физическими контейнерами. Каждый контейнер может содержать материал (список из них, каждый с весами) и/или больше контейнеров, которые имеют вес. Мне нужен общий вес контейнера и все, что он держал. (Я использовал его, чтобы предсказать вес больших рюкзаков, полный снаряжения для кемпинга, без упаковки и взвешивания.) Это было легко сделать с рекурсией и было бы намного сложнее с петлями. Но многие проблемы, которые, естественно, подходят для одного подхода, также могут быть решены с другой.