Каковы реальные проблемы, в которых рекурсивный подход является естественным решением помимо поиска в глубину (DFS)?
(Я не рассматриваю Ханойскую башню , число Фибоначчи или факториальные проблемы реального мира. В моем понимании они немного надуманы.)
Ответы:
Здесь много примеров математики, но вы хотели пример из реального мира , поэтому немного подумав, возможно, это лучшее, что я могу предложить:
Вы найдете человека, который заразился данной контагиозной инфекцией, которая не является смертельной и быстро излечивается (тип A), за исключением одного из пяти человек (мы назовем их типом B), который постоянно инфицирован ею и не показывает симптомы и просто действует как распространитель.
Это создает довольно раздражающие волны хаоса, когда когда-либо тип B заражает множество типов A.
Ваша задача - выследить всех вирусов типа B и провести иммунизацию, чтобы остановить основу болезни. К сожалению, вы не можете назначить общенациональное лекарство для всех, потому что люди, относящиеся к типу А, также имеют смертельную аллергию на лекарство, которое работает для типа В.
То, как вы это сделаете, было бы социальным открытием, если бы инфицированный человек (тип A) выбрал все свои контакты за последнюю неделю, пометив каждый контакт в куче. Когда вы проверяете, что человек заражен, добавьте его в очередь для отслеживания. Если человек относится к типу B, добавьте его в «продолжение» во главе (потому что вы хотите остановить это быстро).
После обработки данного человека выберите человека в начале очереди и при необходимости примените иммунизацию. Получите все их контакты, которые ранее не посещались, а затем проверьте, не заражены ли они.
Повторяйте, пока очередь зараженных людей не станет равной 0, а затем дождитесь новой вспышки.
(Хорошо, это немного итеративно, но это итеративный способ решения рекурсивной проблемы, в данном случае обход в ширину базы населения, пытающийся обнаружить вероятные пути к проблемам, и, кроме того, итерационные решения часто бывают быстрее и эффективнее , и я принудительно удаляю рекурсию повсюду, так что она становится инстинктивной .... черт возьми!)
источник
Пример рекурсии из реального мира
источник
Как насчет чего-либо, связанного со структурой каталогов в файловой системе. Рекурсивный поиск файлов, удаление файлов, создание каталогов и т. Д.
Вот реализация Java, которая рекурсивно распечатывает содержимое каталога и его подкаталогов.
import java.io.File; public class DirectoryContentAnalyserOne implements DirectoryContentAnalyser { private static StringBuilder indentation = new StringBuilder(); public static void main (String args [] ){ // Here you pass the path to the directory to be scanned getDirectoryContent("C:\\DirOne\\DirTwo\\AndSoOn"); } private static void getDirectoryContent(String filePath) { File currentDirOrFile = new File(filePath); if ( !currentDirOrFile.exists() ){ return; } else if ( currentDirOrFile.isFile() ){ System.out.println(indentation + currentDirOrFile.getName()); return; } else{ System.out.println("\n" + indentation + "|_" +currentDirOrFile.getName()); indentation.append(" "); for ( String currentFileOrDirName : currentDirOrFile.list()){ getPrivateDirectoryContent(currentDirOrFile + "\\" + currentFileOrDirName); } if (indentation.length() - 3 > 3 ){ indentation.delete(indentation.length() - 3, indentation.length()); } } } }
источник
Quicksort , сортировка слиянием , и большинство других N сортов N-лог.
источник
Пример Мэтта Дилларда хорош. В более общем смысле, любое хождение по дереву может быть очень легко обработано рекурсией. Например, компиляция деревьев синтаксического анализа, обход XML или HTML и т. Д.
источник
Рекурсия часто используется в реализациях алгоритма обратного отслеживания . Для «реального» применения этого, как насчет решателя судоку ?
источник
Рекурсия уместна, когда проблема может быть решена путем разделения ее на подзадачи, которые могут использовать один и тот же алгоритм для их решения. Алгоритмы на деревьях и отсортированных списках вполне подходят. Многие задачи вычислительной геометрии (и 3D-игр) могут быть решены рекурсивно с использованием деревьев разделения двоичного пространства (BSP), толстых подразделений. или другие способы разделения мира на части.
Рекурсия также уместна, когда вы пытаетесь гарантировать правильность алгоритма. Учитывая функцию, которая принимает неизменяемые входные данные и возвращает результат, который представляет собой комбинацию рекурсивных и нерекурсивных вызовов на входах, обычно легко доказать, что функция верна (или нет), используя математическую индукцию. Часто это невозможно сделать с помощью итеративной функции или с входными данными, которые могут изменяться. Это может быть полезно при работе с финансовыми расчетами и другими приложениями, где точность очень важна.
источник
Конечно, многие компиляторы активно используют рекурсию. Компьютерные языки сами по себе рекурсивны (т. Е. Вы можете встраивать операторы if в другие операторы if и т. Д.).
источник
Отключение / настройка только для чтения для всех дочерних элементов управления в контейнерном элементе управления. Мне нужно было сделать это, потому что некоторые дочерние элементы управления сами были контейнерами.
источник
Известный цикл Eval / Apply от SICP
(Источник: mit.edu )
Вот определение eval:
Вот определение слова apply:
Вот определение eval-последовательности:
eval
->apply
->eval-sequence
->eval
источник
Рекурсия используется в таких вещах, как BSP-деревья для обнаружения столкновений при разработке игр (и других подобных областях).
источник
Люди часто сортируют стопки документов, используя рекурсивный метод. Например, представьте, что вы сортируете 100 документов по именам. Сначала сложите документы в стопки по первой букве, затем отсортируйте каждую стопку.
Поиск слов в словаре часто выполняется рекурсивным методом, аналогичным бинарному поиску.
В организациях начальники часто отдают команды начальникам отделов, а те, в свою очередь, отдают команды менеджерам и т. Д.
источник
Требования реального мира, которые я получил недавно:
Требование А. Реализуйте эту функцию после полного понимания требования А.
источник
Парсеры и компиляторы могут быть написаны методом рекурсивного спуска. Не лучший способ сделать это, поскольку такие инструменты, как lex / yacc, генерируют более быстрые и эффективные парсеры, но концептуально просты и легки в реализации, поэтому они остаются обычными.
источник
Рекурсия применяется к проблемам (ситуациям), где вы можете разбить (сократить) на более мелкие части, и каждая часть (и) выглядит аналогично исходной проблеме.
Хорошими примерами того, где есть более мелкие детали, похожие на самих себя, являются:
Рекурсия - это метод, позволяющий разбивать проблему на все меньшие и меньшие части, пока одна из этих частей не станет достаточно маленькой, чтобы превратиться в кусок пирога. Конечно, после того, как вы разделите их, вам придется снова «сшить» результаты в правильном порядке, чтобы сформировать полное решение вашей исходной проблемы.
Некоторые рекурсивные алгоритмы сортировки, алгоритмы обхода деревьев, алгоритмы сопоставления / сокращения, разделяй и властвуй - все это примеры этой техники.
В компьютерном программировании большинство языков типа «вызов-возврат» на основе стека уже имеют встроенные возможности для рекурсии: т.е.
источник
У меня есть система, которая в нескольких местах использует чистую хвостовую рекурсию для имитации конечного автомата.
источник
Некоторые отличные примеры рекурсии можно найти в языках функционального программирования . В языках функционального программирования ( Erlang , Haskell , ML / OCaml / F # и т. Д.) Очень часто при любой обработке списков используется рекурсия.
При работе со списками в типичных языках императивного ООП очень часто можно увидеть списки, реализованные как связанные списки ([item1 -> item2 -> item3 -> item4]). Однако в некоторых языках функционального программирования вы обнаружите, что сами списки реализуются рекурсивно, где «заголовок» списка указывает на первый элемент в списке, а «хвост» указывает на список, содержащий остальные элементы ( [элемент1 -> [элемент2 -> [элемент3 -> [элемент4 -> []]]]]). На мой взгляд, это довольно креативно.
Эта обработка списков в сочетании с сопоставлением с образцом ОЧЕНЬ эффективна. Скажем, я хочу суммировать список чисел:
По сути, это говорит: «если бы нас вызвали с пустым списком, верните 0» (что позволяет нам прервать рекурсию), иначе верните значение заголовка + значение Sum, вызванного с оставшимися элементами (следовательно, наша рекурсия).
Например, у меня может быть список URL-адресов , я думаю, что разбиваю все URL-адреса, на которые ссылается каждый URL-адрес, а затем уменьшаю общее количество ссылок на / из всех URL-адресов для генерации "значений" для страницы (подход, который Google берет с PageRank, и вы можете найти его определение в исходной статье MapReduce ). Вы также можете сделать это для подсчета количества слов в документе. И многое-многое-многое другое.
Вы можете расширить этот функциональный шаблон на любой тип кода MapReduce, где вы можете взять список чего-либо, преобразовать его и вернуть что-то еще (будь то другой список или какая-то zip-команда в списке).
источник
XML или обход всего, что является деревом. Хотя, честно говоря, я практически никогда не использую рекурсию в своей работе.
источник
Петли обратной связи в иерархической организации.
Начальник говорит топ-менеджменту собирать отзывы от всех в компании.
Каждый руководитель собирает своих прямых подчиненных и просит их собрать отзывы от своих подчиненных.
И дальше по линии.
Люди без прямых подчиненных - листовые узлы в дереве - оставляют свои отзывы.
Отзывы возвращаются вверх по дереву, и каждый менеджер добавляет свой отзыв.
В конце концов, вся обратная связь возвращается к высшему боссу.
Это естественное решение, потому что рекурсивный метод позволяет фильтровать на каждом уровне - сопоставление дубликатов и удаление оскорбительной обратной связи. Главный начальник может отправить глобальное электронное письмо и попросить каждого сотрудника сообщить обратную связь непосредственно ему / ей, но есть проблемы «вы не можете справиться с правдой» и «вы уволены», поэтому рекурсия работает лучше всего.
источник
Предположим, вы создаете CMS для веб-сайта, где ваши страницы имеют древовидную структуру, при этом корень является домашней страницей.
Предположим также, что ваш {user | client | customer | boss} запрашивает, чтобы вы разместили цепочку навигации на каждой странице, чтобы показать, где вы находитесь в дереве.
Для любой данной страницы n вы можете рекурсивно пройти к родительскому элементу n, его родительскому элементу и т. Д., Чтобы создать список узлов до корня дерева страниц.
Конечно, в этом примере вы нажимаете db несколько раз на страницу, поэтому вы можете использовать некоторый псевдоним SQL, где вы просматриваете таблицу страниц как a, а таблицу страниц снова как b и присоединяетесь к a.id с b.parent, чтобы база данных выполняла рекурсивные соединения. Это было давно, поэтому мой синтаксис, вероятно, бесполезен.
Опять же, вы можете просто рассчитать это только один раз и сохранить его вместе с записью страницы, обновляя его только при перемещении страницы. Это, наверное, было бы эффективнее.
В любом случае, это мои 0,02 доллара
источник
У вас есть организационное дерево на N уровней. Проверены несколько узлов, и вы хотите расширить до только тех узлов, которые были проверены.
Это то, что я на самом деле закодировал. С рекурсией это легко и приятно.
источник
В моей работе у нас есть система с общей структурой данных, которую можно описать как дерево. Это означает, что рекурсия - очень эффективный метод работы с данными.
Для ее решения без рекурсии потребуется много ненужного кода. Проблема с рекурсией в том, что нелегко проследить за тем, что происходит. Вы действительно должны концентрироваться, следя за ходом выполнения. Но когда он работает, код получается элегантным и эффективным.
источник
Расчеты по финансам / физике, например, сложные средние.
источник
источник
Разбор дерева элементов управления в Windows Forms или WebForms (.NET Windows Forms / ASP.NET ).
источник
Лучший пример, который я знаю, - это быстрая сортировка , с рекурсией она намного проще. Взгляни на:
shop.oreilly.com/product/9780596510046.do
www.amazon.com/Beautiful-Code-Leading-Programmers-Practice/dp/0596510047
(Щелкните первый подзаголовок под главой 3: «Самый красивый код, который я когда-либо писал»).
источник
Телефонные и кабельные компании поддерживают модель своей топологии проводки, которая, по сути, представляет собой большую сеть или граф. Рекурсия - это один из способов обойти эту модель, когда вы хотите найти все родительские или все дочерние элементы.
Поскольку рекурсия является дорогостоящей с точки зрения обработки и памяти, этот шаг обычно выполняется только при изменении топологии и сохранении результата в формате модифицированного предварительно упорядоченного списка.
источник
Индуктивное рассуждение, процесс формирования понятий, носит рекурсивный характер. Ваш мозг делает это постоянно, в реальном мире.
источник
Аналогично комментарию о компиляторах. Узлы абстрактного синтаксического дерева естественным образом поддаются рекурсии. Все рекурсивные структуры данных (связанные списки, деревья, графики и т. Д.) Также легче обрабатывать с помощью рекурсии. Я действительно думаю, что большинству из нас не удается часто использовать рекурсию после окончания школы из-за типов реальных проблем, но хорошо знать об этом как о возможности.
источник
Умножение натуральных чисел - это реальный пример рекурсии:
источник