рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Рекурсия и стек отложенных заданий

Рекурсия и стек отложенных заданий - раздел Транспорт, От автора Рекурсивные Алгоритмы Далеко Не Всегда Неэффективны, Как Можно Подумать, Проч...

Рекурсивные алгоритмы далеко не всегда неэффективны, как можно подумать, прочитав предыдущий раздел. Во многих задачах рекурсивные процедуры и функции очень полезны, кроме того, они исключительно просто записываются, что также немаловажно. Но каждый раз, когда вы захотите решить с помощью рекурсивного алгоритма более или менее сложную задачу, вы будете сталкиваться с нехваткой памяти в стеке (можно выделить стеку менее 64К байт), а некоторые языки программирования вовсе не разрешают рекурсию. Существует способ запрограммировать рекурсивный по сути алгоритм, не используя рекурсивных подпрограмм, этот прием называется стек отложенных заданий. Здесь термин “стек” означает, конечно, не область памяти, которую компилятор отводит для подпрограмм, а некоторую структуру данных, организованную по принципу LIFO; мы уже работали с такой структурой, когда изучали списки. Стек отложенных заданий не обязательно должен храниться в хипе - если максимальная глубина стека известна заранее и не очень велика, то можно хранить стек в массиве, это еще проще. Мы будем использовать и тот и другой способ. Решим в качестве примера известную задачу о Ханойских башнях. Ханойские башни - это три стержня, на первом из которых надето n дисков постепенно уменьшающегося размера, внизу лежит самый большой диск, на нем диск поменьше и так далее, а наверху самый маленький диск. Требуется перенести все диски на третий стержень, при этом класть больший диск на меньший запрещено. Один из алгоритмов решения этой задачи вполне очевиден: сначала перенесем n-1 дисков на второй стержень (операция 1), затем самый большой диск перенесем на третий стержень (операция 2) и, наконец, перенесем n-1 дисков, которые пока надеты на второй стержень, на третий (операция 3). Одна из операций в этом алгоритме (перенос самого большого диска) тривиальна, но как выполнить остальные две? Это очень просто - для того чтобы переместить n-1 дисков, применим тот же самый алгоритм, что и для перемещения n дисков. Если мы будем использовать рекурсивную подпрограмму, то алгоритм для нее готов, больше ничего придумывать не надо.

 

Procedure Moving(i{количество перемещаемых дисков}, m{откуда перемещаются}, n{куда перемещаются} : Word);

Var s : Word;

Begin

If i=1 Then Begin {тривиальный случай - 1 диск}

Write(m,'-->',n,' '); Exit; End;

s:=6-m-n; {номер третьего стержня (не n и не m)}

Moving(i-1,m,s); {перенесем i-1 дисков на s - операция 1}

Write(m,'-->',n,' ');{перенесем нижний диск на n - операция 2}

Moving(i-1,s,n); {перенесем i-1 дисков c s на n - операция 3}

End;

Const n = 5;

Begin

Moving(n,1,3);

End.

 

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

 

Type

PStack = ^TStack;

TStack = Record

{это стек отложенных заданий, содержащий тройки чисел. Num - сколько дисков переместить, From_ - откуда переместить, To_ - куда переместить. Будем хранить стек в хипе, так как неизвестно, насколько велико значение n}

Num,From_,To_ : Byte;

Next : PStack;

End;

Function EoS(Init : Pointer):Boolean;

{эта функция определяет, пуст стек или нет}

Begin

EoS:=Init=Nil;

End;

Procedure Read_From_Stack(Var Init:PStack; Var Count,n1,n2:Byte);

{эта процедура "забирает" из стека одну тройку чисел - одно задание}

Var ps : PStack;

Begin

Count:=Init^.Num;

n1:=Init^.From_;

n2:=Init^.To_;

ps:=Init;

Init:=Init^.Next;

Dispose(ps);

End;

Procedure Write_To_Stack(Var Init:PStack; Count,n1,n2:Byte);

{процедура записывает в стек одно задание}

Var ps : PStack;

Begin

New(ps);

ps^.Num:=Count;

ps^.From_:=n1;

ps^.To_:=n2;

ps^.Next:=Init;

Init:=ps;

End;

Procedure Moving(i,m,n:Byte);

Var

Init : PStack;

j,p,q,s : Byte;

Begin

Init:=Nil; {стек делаем пустым}

Write_To_Stack(Init,i,m,n);

{кладем в стек задание - переложить все диски с m на n}

While Not EoS(Init) Do Begin {пока в стеке есть задания}

Read_From_Stack(Init,j,p,q); {берем задание из стека}

If j=1 Then Write(p,'-->',q,' '){тривиальный случай}

Else Begin

s:=6-p-q; {вычисляем номер свободного стержня}

Write_To_Stack(Init,j-1,s,q);

{кладем в стек задание на операцию 3}

Write_To_Stack(Init,1,p,q);

{кладем в стек задание на операцию 2}

Write_To_Stack(Init,j-1,p,s);

{кладем в стек задание на операцию 1}

End;

End;

End;

Const n=5;

Begin

Moving(n,1,3);

End.

 

Итак, мы заменили рекурсию стеком отложенных заданий, “неправильная”последовательность операторов Write_to_Stack - это не ошибка: задание, которое надо будет выполнить первым, мы должны класть туда в последнюю очередь (принцип стека: последним вошел - первым вышел). Этот прием можно использовать в очень многих задачах, для которых известны рекурсивные алгоритмы, мы еще встретимся с ним в следующих разделах.

– Конец работы –

Эта тема принадлежит разделу:

От автора

B r... Теперь мы можем присвоить переменным их значения...

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Рекурсия и стек отложенных заданий

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

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

Round(x) - округленное до целого вещественное число, преобразованное к типуLongInt
6. Sqr(x) - квадрат числа 7. Sqrt(x) - квадратный корень 8. Exp(x) - экспонента 9. Ln

Символьный тип данных
Для хранения символьной информации в Паскале предусмотрен специальный тип данных Char. Допустимы переменные, нетипизированные и типизированные константы такого типа. Данные типа

Caseвыражение Of
список значений : оператор/блок .................................. список значений: оператор/блок

Процедуры и функции. Сфера действия описаний
В языке Паскаль (как вы уже поняли из предыдущего материала) существуют понятия процедуры и функции. Процедуры и функции можно определить как замкнут

Открытые массивы и нетипизированные параметры
Из предыдущего раздела мы узнали, что параметры подпрограмм описываются как [Var] имя : имя типа , это правда, но не вся правда - существует еще два

Множества
Понятие множества в Паскале очень близко к математическому определению: множество - это совокупность однотипных неиндексированных объектов. Множества

Графические средства языка Паскаль
Монитор персонального компьютера может работать в двух режимах - текстовом и графическом. Все, что мы делали до сих пор, мы делали в текстовом режиме. Текстовый экран содержит 2000 знако

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

Case тип Of
константа 1 : (описание поля); константа 2 : (описание поля); .....................

Модуль Crt
Crt - еще один стандартный модуль Паскаля, в котором содержатся разнообразные средства консольного ввода-вывода (то есть ввода с клавиатуры и вывода на текстовый экран). Процедуры

Var TextAttr : Byte
В ней содержится текущий цвет фона и цвет символов, используемые при выводе на экран процедурами Write иWriteLn. Изменив эту переменную, вы задаете новый

Другие средства обработки файлов и модуль DOS
Для того чтобы определить, есть ли на диске файл с заданным именем, удобно использовать уже известную нам стандартную функцию IOResult , которая возвращает ноль при успешном завершении последней оп

Type SearchRec=Record
Fill : Array[1..21] of Byte; Attr : Byte; Time : LongInt; Size : LongInt; Name : Stri

Процедурные типы
Язык Паскаль позволяет использовать в программе данные типа “процедура” или типа “функция”. Такие данные можно передавать как аргументы подпрограмм, можно описывать и использовать массивы процедур

Указатели и динамическая память
Указателями называются переменные и константы, значениями которых являются адреса. Различаются два вида указателей - обобщенные указатели и

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

Открытые строки
  Открытыми строками, или длинными строками, или C-строками, называются символьные последовательности длиной до 65535 символов, ограниченные справа нуль-символ

Использование командной строки и вызов внешних программ
Паскаль позволяет передавать информацию в программу при ее запуске через командную строку. Для этого служат две стандартные функции -ParamCount и ParamStr.

Обработка программных прерываний
Программное прерывание - это ситуация, возникающая, когда дальнейшее выполнение программы невозможно. Например, деление на ноль, переполнение, ошибка Range check error, обращение по неверному адрес

Объекты
Объектом в языке Паскаль называется совокупность данных и подпрограмм, обрабатывающих эти данные. Программирование с использованием объектов называется объектно-о

Type имя типа=Object
описание полей описание методов End; Поля объектов описываются так же, как поля записей, а описание метода - это заголовок процедуры или функции. Сами методы распол

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

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

Комбинаторные алгоритмы
В этом разделе мы рассмотрим три наиболее важные задачи комбинаторики: нахождение всех подмножеств множества из n элементов; нахождение всех выборок по m элементов из n элементов и нахождение всех

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

Упорядоченные бинарные деревья и приоритетные очереди
Упорядоченным бинарным деревом, или бинарным деревом поиска, называют дерево, в любой части которого элементы левого поддерева меньше корневого элеме

Алгоритмы сортировки
В этом разделе мы рассмотрим различные алгоритмы решения задачи сортировки. Задача сортировки ставится следующим образом: дана последовательность записей R1,R

Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • Популярное
  • Облако тегов
  • Здесь
  • Временно
  • Пусто
Теги