Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
59
Добавлен:
06.02.2016
Размер:
169.98 Кб
Скачать

4. Примеры решения задач с помощью рекурсии “Ханойская башня”

При написании рекурсивных программ, следует помнить, что при рекурсивном вызове процедурой самой себя или другой процедуры следует соблюдать определённые “правила предосторожности”. Рекомендуется компилировать программу с директивой {$S+}. Эта директива включает проверку переполнения стека (области памяти, в которой хранится состояние вызывающей подпрограммы). Если в процессе выполнения программы происходит переполнение стека, вызов процедуры или функции, откомпилированной с опцией {$S+}, приводит к завершению работы программы, а на дисплей выдаётся сообщение об ошибке. Полезно также использовать директиву {$R+}, включающую проверку диапазона переменных. В начале каждой процедуры (функции), вызываемой рекурсивно, можно разместить строку if keypressed then Halt. В этом случае при зависании программы вместо перезагрузки будет достаточно нажать любую клавишу.

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

Рассмотрим пример. Правила головоломки “Ханойская башня” таковы. Имеется доска с тремя колышками. На первом из них нанизано несколько дисков убывающего диаметра (самый большой находится внизу – рис. 5).

Требуется расположить диски в том же порядке на третьем колышке, причём диски разрешается перекладывать только по одному, а класть большой диск на меньший нельзя. Один колышек используется в качестве вспомогательного. Ответим на вопрос – сколько перемещений дисков следует выполнить?

Алгоритм решения головоломки следующий:

  1. Переместить верхние n-1 дисков на второй колышек.

  2. Нижний диск с первого колышка переместить на третий.

  3. Переместить n-1 дисков на третий колышек, используя первый в качестве вспомогательного.

  4. Повторять, пока на третьем колышке не будет сформирована новая пирамида.

Исходная задача сводится, таким образом, к двум задачам о переносе n-1 диска и одной задаче о переносе одного диска. Для n-1 требуется одно перемещение. Исходный текст программы для вычисления количества ходов приведён ниже (Листинг 1). Количество ходов здесь может быть вычислено как с применением рекурсии (функция hanoi1), так и без неё (функция hanoi2). В первом случае исходный текст функции короче.

1 2 3

Рис. 5. Головоломка “Ханойская башня”

Листинг 1. Программа “Ханойская башня”

{$S+}

program hanoi_moves;

function hanoi1(n: Word): LongInt;

begin

if n=1 then hanoi1:=1

else hanoi1:=2*hanoi1(n-1)+1;

end;

function hanoi2(n: Word): LongInt;

var j: LongInt; k: Word;

begin

if n=1 then hanoi2:=1

else

begin

j:=1;

for k:=2 to n do j:=2*j+1;

hanoi2:=j;

end;

end;

writeln(hanoi1(20));

writeln(hanoi2(20));

end.

Двумерное множество Кантора

Ещё один пример использования рекурсии приводится в программе Cantor (Листинг 2), которая строит двумерное множество Кантора. Множество строится следующим образом. Имеется квадрат, внутренняя часть которого закрашена каким-то цветом. Этот квадрат делится на 16 равных частей (тоже квадратных). Затем удаляются 4 средних квадрата, причём изображения их границ остаются. Далее процедура повторяется для каждого оставшегося квадрата. Алгоритм построения квадратного множества Кантора следующий:

  1. Построить квадрат размером L.

  2. Вырезать расположенный в центре квадрат размером L/2.

  3. Разделить исходный квадрат на четыре равные части размером L/2.

  4. Для каждого из четырёх квадратов повторить шаги 2 и 3.

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

Процедура SetWriteMode модуля Graph устанавливает режим вывода линии. Режим задаётся с помощью логической операции. В нашем примере используется операция “исключающее ИЛИ” (ей соответствует константа xorput), поэтому изображение линии комбинируется с изображением, уже выведенным на экран.

Листинг 2. Программа “Двумерное множество Кантора”

{$S+}

program Cantor;

uses Crt, Graph, graphs;

var ch: Char;

const min_size=1;

procedure draw(x,y: integer; size: Word);

var s: Word;

begin

if size>min_size then

begin

s:=size div 2;

draw(x-size, y+size, s);

draw(x-size, y-size, s);

draw(x+size, y+size, s);

draw(x+size, y-size, s);

end;

rectangle(x-size, y-size, x+size, y+size,);

bar(x-size+1, y-size+1, x+size-1, y+size-1);

end;

begin

open_graph;

SetFillStyle(solidfill, black);

SetColor(White);

draw(GetMaxX div 2, GetMaxY div 2, GetMaxY div 4);

OutTextXY(265, 235, ‘Press <Space>’);

ch:=ReadKey;

SetColor(Black);

SetWriteMode(xorput);

draw(getmaxx div 2, getmaxy div 2, getmaxy div 4);

SetColor(White);

OutTextXY(265, 235, ‘Press <Space>’);

ch:=ReadKey;

close_graph;

end.

Соседние файлы в папке 2_semestr_lection