Рекурсивные процедуры — Visual Basic

Twitter LinkedIn Facebook Адрес электронной почты

  • Статья
  • Чтение занимает 2 мин

Рекурсивная процедура — это процедура, вызывающая себя. Как правило, это не самый эффективный способ написания кода Visual Basic.

Следующая процедура использует рекурсию для вычисления факториала исходного аргумента.

Function Factorial(n As Integer) As Integer
    If n <= 1 Then
        Return 1
    End If
    Return Factorial(n - 1) * n
End Function

Рекомендации по рекурсивным процедурам

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

Использование памяти. Приложение имеет ограниченный объем пространства для локальных переменных. Каждый раз, когда процедура вызывает себя, она использует больше этого пространства для дополнительных копий своих локальных переменных. Если этот процесс продолжается бесконечно, в конечном итоге возникает StackOverflowException ошибка.

Эффективность. Вы почти всегда можете использовать цикл вместо рекурсии. Цикл не имеет дополнительных затрат на передачу аргументов, инициализацию дополнительного хранилища и возврат значений. Производительность может быть гораздо лучше без рекурсивных вызовов.

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

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

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

См. также

  • StackOverflowException
  • Процедуры
  • Подпрограммы
  • Процедуры функций
  • Процедуры свойств
  • Процедуры операторов
  • Параметры и аргументы процедуры
  • Перегрузка процедур
  • Рекомендации по устранению неполадок
  • Циклические структуры

Рекурсивные процедуры в языке Пролог | Практическая информатика

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

Гравюра голландского художника Мориса Эшера «Рисующие руки» — одна из лучших иллюстраций понятия рекурсии. Всем известный стишок о попе и его собаке демонстрирует нам бесконечность рекурсивных вызовов. Используя рекурсию как прием программирования мы должны быть уверены, что рекурсивная процедура будет завершена.

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

На примере уже имеющейся у нас базы данных объясним преимущества использования рекурсии и особенности рекурсивных правил. Пусть имеются следующие факты:

больше(слон, лошадь).
больше(лошадь, осел).
больше(осел, собака).
больше(осел, обезьяна).

Выполним запрос к базе данных

?- больше(осел, собака).
Yes

Цель больше(осел, собака) была достигнута потому, что этот факт был сообщен Прологу при загрузке базы. Теперь проверим, больше ли обезьяна слона?

?- больше(обезьяна, слон).
No

Нет, не больше. Мы получили такой ответ, какой и ожидали: соответствующий запрос, а именно больше(обезьяна, слон) не подтвердился. Но, что случится, если мы зададим вопрос по-другому?

?- больше(слон, обезьяна).
No

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

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

больше(слон, обезьяна).

Для нашего маленького примера это означает добавление еще 5 фактов.

Однако гораздо лучшим решением будет добавление в программу нового отношения, которое мы назовем больше_2. Животное X больше, чем животное Y, если это определено как факт (первое правило) или существует животное Z, для которого определен факт, что животное X больше, чем животное Z и может быть показано, что животное Z больше, чем животное Y (второе правило). На Прологе это запишется так:

больше_2(X, Y) :- больше(X, Y).
больше_2(X, Y) :- больше(X, Z), больше(Z, Y).

Если в цепочке участвуют не три, а большее число объектов, то придется добавить новые правила:

больше_2(X, Y) :- больше(X, Z1), больше(Z1, Z2), 
 больше(Z2, Y).
больше_2(X, Y) :- больше(X, Z1), больше(Z1, Z2),
 больше(Z2, Z3), больше(Z3, Y).
...

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

Поэтому воспользуемся более корректной и элегантной формулировкой. Ключевая идея здесь — определить отношениебольше_2с помощью его самого. Теперь второе (и последнее!) правило выглядит так:

больше_2(X, Y) :- больше(X, Z), больше_2(Z, Y).

Таким образом, итоговая программа будет иметь вид

больше_2(X, Y) :- больше(X, Y). 
больше_2(X, Y) :- больше(X, Z), больше_2(Z, Y).

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

ERROR: Out of local stack

Если теперь в запросе использовать предикат больше_2 вместо больше, то программа будет работать так, как и предполагалось:

?- больше_2(слон, обезьяна).
Yes

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

 е. с его головой). После этого двум переменным присваиваются значения: X = слон и Y = обезьяна.

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

В данном случае Пролог не может найти в базе данных факта больше(слон, обезьяна) и переходит к рассмотрению второго правила. Оно гласит, что для того, чтобы получить ответ на вопрос больше_2(X,Y) (с фиксированными значениями переменных, то есть больше_2(слон, обезьяна)), Пролог должен ответить на два подвопросабольше(X, Z) и больше_2(Z, Y), опять же с соответствующими значениями переменных. Процесс просмотра базы знаний с самого начала повторяется до тех пор, пока факты, составляющие цепочку между слон и обезьяна, не будут найдены, а запрос успешно обработан.

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

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


Задание
Дана база данных «Родители», в которой предикат родитель(коля, андрей) означает, что Коля является родителем Андрея:

родитель(коля, андрей). 
родитель(андрей, саша).
родитель(виктор, федор).
родитель(виктор, петр).
родитель(петр, елена).

Используя рекурсию, определите отношение предок/2 через отношение родитель/2. Будем говорить, что некоторый X является отдаленным предком некоторого Y, если между X и Y существует цепочка людей, связанных между собой отношением родитель — ребенок.

Рекурсивные процедуры — Visual Basic

Редактировать

Твиттер LinkedIn Фейсбук Электронная почта

  • Статья
  • 2 минуты на чтение

рекурсивная процедура вызывает сама себя. В общем, это не самый эффективный способ написания кода Visual Basic.

Следующая процедура использует рекурсию для вычисления факториала исходного аргумента.

 Факториал функции (n как целое число) как целое число
    Если n <= 1 Тогда
        Возврат 1
    Конец, если
    Вернуть факториал (n - 1) * n
Конечная функция
 

Рекомендации по рекурсивным процедурам

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

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

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

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

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

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

См. также

  • StackOverflowException
  • Процедуры
  • Подпроцедуры
  • Функциональные процедуры
  • Процедуры собственности
  • Процедуры оператора
  • Параметры процедуры и аргументы
  • Перегрузка процедуры
  • Процедуры устранения неполадок
  • Петлевые конструкции

Обратная связь

Просмотреть все отзывы о странице

РЕКУРСИВНАЯ Процедура

РЕКУРСИВНАЯ Процедура

Процедуры Fortran могут быть РЕКУРСИВНЫМИ, что означает, что они могут прямо или косвенно вызывать самих себя. Необходимо использовать ключевое слово RECURSIVE. в объявлении процедуры.

Описание

Объявление RECURSIVE процедуры подразумевает, что процедура может вызывать сама себя.

  

Синтаксис

РЕКУРСИВНАЯ ПОДПРОГРАММА подимя ( [dummy-args] )
или
RECURSIVE [спецификация типа] FUNCTION имя-функции ( [dummy-args] ) [ РЕЗУЛЬТАТ (имя результата ) ]
Где:

подимя — это имя подпрограммы.

dummy-args — список имен фиктивных аргументов, разделенных запятыми.

тип-спецификация есть

INTEGER [селектор типа] REAL [селектор вида] DOUBLE PRECISION КОМПЛЕКС [тип-селектор] СИМВОЛОВ [символ-селектор] ЛОГИЧЕСКИЙ [вид-селектор] ТИП ( имя типа )

вид-селектор есть ( [ ВИД = ] вид )

char-selector is ( [ LEN= ] длина [ , ) KIND= вид] )

или (ВИД = вид [ , LEN= длина ] ) или * длина символа []

вид — это скалярное целочисленное выражение, которое можно вычислить во время компиляции.

длина - это скалярное целочисленное выражение или *

char-length — скалярная литеральная константа INTEGER или (*)

имя-функции — это имя функции.

имя-результата — это имя переменной результата.

Примечания

Ключевое слово RECURSIVE должно присутствовать, если процедура прямо или косвенно вызывает себя или процедуру, определенную оператором ENTRY в той же подпрограмме. РЕКУРСИВНЫЙ также должен присутствовать, если процедура определена оператором ENTRY прямо или косвенно. вызывает себя, другую процедуру, определенную оператором ENTRY, или процедуру определяется объявлением процедуры.

Результат

Если рекурсивная процедура является функцией, результатом является тип и вид объявления функции или переменной результата.