Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Spec_Mov_3k_4k_Lect.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
1.46 Mб
Скачать

Виды рекурсий Рекурсии по значению и по аргументам

В реализации рекурсивных функций различают:

  • рекурсию по значению

  • рекурсию по аргументам.

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

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

Простая рекурсия

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

Примеры

Вычисление длины списка:

(sexpr length (lambda (x)

(cond ((atom x ) 0) ; x – aтом или mib

(T (add1 (length (cdr x )))) )

))

В данном случае length рекурсивна по аргументу, т.к. вызов length стоит на месте аргумента функции add1, добавляющей единицу к своему аргументу.

Вычисление копии списка:

(sexpr copy ( lambda (lst)

(cond (( null lst) nil )

(T (cons (car lst)(copy (cdr lst )))))

))

Действительноно вычисляется копия, т.к. функция cons создает cons-ячейку, в которой содержатся 2 указателя,- первый - на результат вычисления 1-го аргумента и второй – на результат вычисления 2-го аргумента:

Определение принадлежности элемента х списку y:

(sexpr member (lambda (x y )

(cond ((null y) nil) ; список пуст

((equal x (car y)) t) совпадает с 1-м

(t ( member x ( cdr y))) )

))

Функция member рекурсивна по значению.

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

Пример

Функция invlist обращает исходный список Х. (Если элементы списка в свою очередь являются списками, то элементы этих последних не обращаются).

Сделаем анализ случаев:

  1. Если x = nil , то результат nil.

  2. Если x ≠ nil, то

а) Пусть z = invlist (cdr(x)),

б) Результат add_to_list(z, car (x)).

Где add-to-list добавляет элемент в конце списка.Имеем:

(sexpr invlist (lambda (x)

(cond ((null x) nil)

(t (add_to_list (invlist (cdr x ))( car x )))

)))

(sexpr add-to-list (lambda (lst elm)

(cond ((null lst) (cons elm nil))

(t (cons(car lst)(add_to_list (cdr lst) elm))))

))

Проанализировать сомостоятельно, что делает функция add_to_list.

Вместо выражения (cons elm nil) в примере представленном выше можно использовать (list elm). Функция list встроенная, Лисповская, и число аргументов для list произвольно.

Параллельная рекурсия

Рекурсия параллельная, когда тело определения функции f содержит вызов функции g, несколько аргументов которой являются рекурсивными вызовами функции f:

(sexpr f (lambda (x1 x2 … xn)(…(g…(f…)…(f…)…)…)))

Пример

Определяется функция deep_copy, реализующая «глубинную копию» списка-аргумента. Ранее был рассмотрен пример реализации «поверхностной копии».

(sexpr deep_copy (lambda (lst)

(if (atom lst) lst

(cons (deep_copy (car lst)) (deep_copy (cdr lst))))

))

Взаимная рекурсия

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

(sexpr f(lambda (…)(…(g…)…)))

(sexpr g(lambda (…)(…(f…)…)))

Пример

Выполняется обращение списка и всех его подсписков.

(sexpr rev (lambda (lst)

(if (atom lst) lst

(replace lst nil)) ))

(sexpr replace (lambda (isx rez)

(if (null isx) rez

(replace (cdr isx) (cons (rev (car isx)) rez)))

))

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

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