Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Комплект Информатика / Курс лекций.doc
Скачиваний:
128
Добавлен:
22.05.2015
Размер:
4.8 Mб
Скачать

2 Управление рекурсией

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

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

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

3 Разработка рекурсивных процедур

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

procedure FindExit (<лабиринт>)Продвигаться по лабиринту до развилки, тупика или выхода; В каждом из указанных случаев выполнить соответствующие инструкции из числа приведенных ниже:

case 1: достигнут выход: (сообщить "выход найден")

case 2: достигнут тупик: (сообщить "неудача")

case 3: достигнута развилка:

(while (есть ветвь, ведущая к неисследованной территории, и выход еще не найден) do (применить процедуру FindExit к лабиринту, представленному одной из неисследованных ветвей;

if (эта процедура сообщила, что выход найден) then (сообщить "выход найден".)

)

if (все варианты этой развилки неудачны) then (сообщить "неудача") )

Рисунок 6 - Лабиринт

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

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

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