Скачиваний:
24
Добавлен:
26.09.2019
Размер:
774.14 Кб
Скачать

Примеры рекурсивных программ

1. Рассмотрим программу, применимую целого:

F (x) = if х=0 then 1

else х·F(х-1)

Для иллюстрации работы данной программы выполним ее, например, для х=4:

2. Функция Аккермана. Эта функция применима целых.

А(х,у) = if х=0 then у+1

else if y=0 then A(x-1,1)

else A(х-1, A(x, y-1))

Проследим, каким образом выполняется эта программа для х=1, у=2.

А(1,2)=А(0, А(1,1))=А(0, А(0, А(1,0)))=

=А(0, А(0, А(0,1)))=А(0, А(0,2))= А(0,3) =4

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

А(1, 2) = А(0, А(1,1)) = А(1,1) + 1 =

= А(0, А(1,0)) + 1= (А(1,0) +1) + 1 =

= А(0,1) + 2 = 2 + 2 = 4

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

Рассмотрим следующую функцию, применимую целых:

F (x,у) = if х=0 then 0

else F(0, F(х,у))

Проследим за вычислением F, используя два различных правила вычисления:

  1. при предпочтении внешнему обращению

F (1,1) = F(0, F(1,1))=0;

  1. при предпочтении внутреннему обращению.

F (1,1) = F(0, F(1,1))= F(0, F(0,F(1,1)))=…

Таким образом, в первом случае последовательность конечна и функция А=0, во втором случае вычисления не заканчиваются.

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

6.2.Рекурсивные программы работы со списками Списки и операции над ними

Большинство рекурсивных алгоритмов связано с работой со списками в силу рекурсивного определения самих структур данных - списков. Для описания этих алгоритмов введем следующую нотацию.

Список – это набор объектов, отделенных друг от друга пробелами и заключенных в квадратные скобки []. Объектами, входящими в такие списки, являются атомы (неделимые элементы) или другие списки.

Атом – это строка буквенно-цифровых символов, не содержащая пробелы.

Для того чтобы отличать атомы от переменных, будем считать, что переменные записываются строчными буквами, а атомы – прописными. Например, [А В С] – список из трех элементов, каждый из которых является атомом. [А [В А [С]]D] – список, в котором на верхнем уровне три элемента: второй элемент сам является списком из трех элементов, в котором третий элемент – это список из одного элемента С.

Для пустого списка, т.е. списка, не содержащего одного элемента, выделяется специальное имя nil.

Наиболее распространенными операциями над списками и атомами являются следующие.

  1. Проверка на равенство:

[А В] = [А В] выдает true ,

[А В] = [В А] и во всех других случаях - false.

  1. Проверка аtom(х) - применима к любым объектам: атомам или спискам. Выдает true, если х является атомом или пустым списком.

  2. Саr(l) применима к любому непустому списку. В качестве результата выдается первый на верхнем уровне элемент этого списка:

Саr([А В С])=А;

Саr([[А В]С D])=[А В];

Саr(nil) и Саr (А) – не определены.

  1. Cdr(l) – применима к любому непустому списку l; результатом является список, полученный из списка l путем исключения первого элемента: Cdr([А В С]) = [В С].

  2. Соns(х,l) - объединяет элемент х со списком l:

Соns(А, [D E]) = [А D Е];

Соns([А В], [D E]) = [[А В] D E].

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]