Чи можна всі рекурсивні функції кодувати ітераціями? [зачинено]


10

Які переваги рекурсії?

Деякі мови програмування можуть оптимізувати хвостову рекурсію, але, загалом кажучи, рекурсія споживає більше ресурсів, ніж звичайні петлі.

Чи можливо мати ітераційну версію якоїсь рекурсивної функції?



Відповіді:


10

Так, ви можете кодувати рекурсивні функції як ітерації. В основному це вимагає, щоб ви підтримували інформацію вручну, що інакше було б опікуватися методом виклику коду, згенерованого компілятором.

Іншими словами, вам потрібен стек, де кожен запис - це структура, що містить передані параметри та всі локальні змінні. Ви завжди працюєте над найпопулярнішим записом на стеці. Якщо вам потрібно зателефонувати собі, створіть новий запис і поставте зверху стек. Після завершення візьміть верхній запис стека, що відкриває нижченаведене, і використовуйте попередньо верхній запис для вилучення значень, що повертаються, та відповідно оновіть новий самий верхній запис.

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


Я розумію. Отже, яка перевага мала б рекурсію? Простота?
OscarRyz

2
@OscarRyz: Так, і це елегантніше.
Майкл К

@OscarRyz, як я описав це рекурсія. Це просто не робиться з нативними процесорними інструкціями. Якщо це зробити вручну, ви можете робити такі речі, як паралелізація, що погано відображається до рідних інструкцій.

15

Рекурсія часто є більш природним способом погляду на речі, ніж ітерація. Наприклад, розглянемо внутрішнє обхід бінарного дерева: inorder(left); process(); inorder(right);набагато простіше, ніж явно підтримувати стек.

Поки ви не заглиблюєтесь занадто глибоко (видуваючи стек), різниця у використанні ресурсів зазвичай тривіальна. Не турбуйтеся про це взагалі. Простий код зазвичай краще, ніж оптимізований рукою код, хоча є винятки. Правильно, як правило, краще, ніж швидко.

Будь-який рекурсивний алгоритм може бути виражений як ітеративний алгоритм, але вам може знадобитися зберігати явний стек (відповідний стеку викликів, який обробляється неявно). Зрештою, якщо ви компілюєте рекурсивну функцію, ви отримуєте щось, що залежить від маніпулювання стеком і циклічного перегляду функції, і це є ітераційним.

Хвосто-рекурсивні функції можна легко перевести в петлі, і їм не потрібен стек, але це особливий випадок.


8
Я б сказав, що право завжди краще, ніж швидко. Код, який робить неправильну справу дуже швидко, нікому не дуже корисний.
Мейсон Уілер

1
Але що робити, якщо ви можете зробити цю неправильну справу дуже швидко ?!
RationalGeek

1
@jkohlhepp - Я можу вирішити будь-яку проблему миттєво. Відповідь 0.
Зауважте, що самостійно подумайте над ім'ям

2
Використання рекурсії, а не явного стека, може бути більш ефективним - уникаючи необхідності виділення купи, можливої ​​фрагментації пам'яті та можливих проблем з локальністю. Однак, "правильно зазвичай краще, ніж швидко", переповнення стека у випадках, коли ваше програмне забезпечення потребує обробки, означає, що ваш код порушений. Зазвичай проблемні випадки досить легко помітити - рекурсія на (розумно) збалансованому дереві є прекрасною, але рекурсія на дереві, яке може бути дуже неврівноваженим, або у зв’язаному списку, може бути серйозною помилкою на мові, як C. Гірше , він може пережити просте тестування, і вийти з ладу лише при реальному розгортанні.
Steve314

1
Я думаю, ви всі розумієте, що мав на увазі Мейсон, і просто жартуєте заради цього. Звичайно, повільна правильна програма корисніша, ніж швидка неправильна програма.
Джорджіо

4

Які переваги рекурсії?

Спробуйте вирішити проблему Тауер Ханой ітеративно. Після того, як ви відмовитесь, подивіться на ітераційне рішення та порівняйте його з рекурсивним. Який простіший?

Чи можливо мати ітераційну версію якоїсь рекурсивної функції?

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


3

Які переваги рекурсії?

Простота. Без оптимізації хвостових викликів, звичайно, потрібно більше ресурсів (стек), але як би ви реалізували, скажімо, deltreeна Java без рекурсії? Поворот полягає в тому, що вони delete()можуть видаляти каталоги, лише якщо вони порожні; ось це з рекурсією:

deltree(File fileOrDirectory) {
    if (fileOrDirectory.isDirectory()) {
        for (File subFileOrDirectory : fileOrDirectory.listFiles()) {
            deltree(subFileOrDirectory);
        }
    }
    fileOrDirectory.delete();
}

1
З стеком, як згадують інші відповіді.
Ніколь

Так, але наскільки це просто? -)
Joonas Pulakka

О, рекурсія, безумовно, краща. Я думав, ти кажеш, що це неможливо.
Ніколь

0

Я вважаю, що рекурсія - це один із тих інструментів, якими повинен жити програміст. За допомогою рекурсії ви можете «продумати» свої алгоритми та вирішити їх так, як ви про це думали. Але, зауважу, усі говорять про те, наскільки хороша рекурсія і скільки простоти приносить код, щодо цього я маю сказати кілька речей:

  1. Перш за все, продумати "рекурсивний шлях" алгоритму непросто. Побудова такої функції, як фабрика (n!) Або щось на кшталт Ханойських веж - лише вершина айсберга, а для досягнення дна потрібен довгий час.
  2. Не думайте, що рекурсія приносить простоту лише вашому коду, іноді ітеративний спосіб некрасивий і безладний, але економічно ефективний (погляньте на рекурсивне рішення проблеми Фібоначчі)

Маючи це на увазі, вивчіть рекурсію! це смішно, складно, і це розгромить ваш мозок !, але ви виявите, що любите це.

Удачі!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.