
- •Теоретический раздел лекции Тема 1. Программирование с использованием рекурсии
- •1.1. Cтратегии решения задачи разбиением ее на подзадачи
- •1.2. Программирование рекуррентных соотношений
- •Var z:extended;
- •1.3. Условия окончания рекурсии
- •1.4. О целесообразности использования рекурсии
- •Var I,X,y,z:word;
- •1.5 Правила выбора программной реализации рекуррентных соотношений
- •Тема 2. Задачи перебора вариантов
- •2.1. Модель дерева решений
- •2.2. Задача оптимального выбора (задача о рюкзаке)
- •2.3. Метод полного перебора двоичного дерева
- •Var wt,ct:extended;
- •Var j,k:byte;
- •If k in s then begin
- •Var j:byte;
- •Var j:byte;
- •Var wt1,oct1:byte;
- •2.4. Метод ветвей и границ
- •Var n,I:byte;
- •Var wt1,oct1:Extended;
- •Include(s,I);
- •If I in Sopt then writeln(I,a[I].W,a[I].C);
- •2.5. Эвристические методы
- •Тема 3. Поиск и сортировка массивов записей
- •3.1. Применимость сортировки и поиска
- •3.2. Массив записей и поиск в нем
- •Var m:word;
- •3.3. Сортировки массивов
- •Var c: mas; I,j,k:word;
- •Var m:word;
- •Var I,j:Word;
- •Var I,j,l,r:Word; X:Tk; w:Tzp;
- •Тема 4. Связанные списки с использованием рекурсивных данных
- •4.1. Список, стек, очередь
- •4.2. Списки на основе динамических массивов
- •Inherited create;
- •Var turn:Tlist; с1,c2:Tinf;
- •4.3. Рекурсивные данные и однонаправленные списки
- •Inherited create;
- •Var stec,st1,turn,tr1:Tlist; inf:Tinf;
- •4.4. Начальное формирование, добавление и удаление элементов однонаправленного списка
- •4.5. Разновидности связанных списков
- •Inf:Tinf;
- •Тема 5. Поиск и сортировки на связанных линейных списках
- •5.1. Поиск в однонаправленных списках
- •5.2. Сортировка однонаправленных списков
- •1 3Var Inf:tInf;
- •Тема 6. Использование линейных связанных списков
- •6.1. Вычисления арифметических выражений
- •Var ch,ch1,ch2,chr:char;
- •I:byte;ch,ch1:char;
- •6.2. Сложение больших целых чисел
- •Var u,V,s,t:byte;
- •6.3. Работа с разреженными матрицами
- •Inf:Tinf;
- •Inf:tInf;
- •Var proot,p:Ptree;
- •Var bl:boolean;
- •7.2. Бинарное дерево поиска
- •7.3. Основные операции с бинарным деревом поиска
- •Inf:tInf;
- •Var d1:Tree; c:Tinf; k:Tkey;
- •Var bl:Boolean;
- •Var m:Word;
- •Var p:Ttree; m:Word;
- •Тема 8. Хеширование
- •8.1. Что такое хеширование
- •8.2. Схема хеширования
- •Interface
- •Inf:Tinf;
- •8.4. Другие способы хеширования
- •Практический раздел Указания по выбору варианта
- •Индивидуальные практические работы и контрольные работы
- •Индивидуальная практическая работа №1. Программирование с использованием рекурсии
- •1.1. Понятие рекурсии
- •1.2. Порядок выполнения работы
- •1.2.1. Пример решения задачи
- •Индивидуальная практическая работа №2. Организация однонаправленного списка на основе рекурсивных типов данных в виде стека
- •2.1. Основные понятия и определения
- •Inf:tInf; // информация
- •Контрольная работа №1. Программирование с использованием деревьев на основе рекурсивных типов данных
- •1.1. Понятие древовидной структуры
- •Inf:tInf;
- •1.2. Компонент tTreeView
- •1.3. Бинарное дерево поиска
- •Основные операции с двоичным деревом поиска
- •1.4. Порядок написания программы
- •Inf:tInf;
- •Inherited Free;
- •Var tr:Ttree;
- •1.5. Индивидуальные задания
- •Курсовая работа
- •Литература
Теоретический раздел лекции Тема 1. Программирование с использованием рекурсии
1.1. Cтратегии решения задачи разбиением ее на подзадачи
Рекурсивным называется описание объекта, частично состоящее и определяемое с помощью самого описываемого объекта. После того, как вы познакомитесь с рекурсией, вы обнаружите, что она встречается достаточно часто.
В математике рекурсивные определения представляют собой мощный аппарат. Как правило, они приводят к рекуррентным соотношениям.
Соотношения, связывающие одни и те же функции, но с различными аргументами, называются рекуррентными соотношениями, или рекуррентными уравнениями.
Рекуррентное уравнение называется правильным, если значения аргументов у любой из функций в правой части соотношения меньше значения аргументов у любой из функций в левой части соотношения; если аргументов несколько, то достаточно уменьшение одного из них.
Например: F(n,x)=F(n/2,x) если n четное
F(n,x)=F((n+1)/2,x) если n нечетное.
Приведем несколько общеизвестных примеров описания объектов с помощью рекуррентных уравнений.
1. Натуральные числа:
а) N(1)=1 есть натуральное число;
б) N(n)=N(n-1)+1, число следующее за натуральным - натуральное число.
2.
Сумма
а) S(0)=a0;
б) S(n)=S(n-1)+an.
3. Числа Фиббоначи: а) b(0)=0; b(1)=1;
б) b(n)=b(n-1)+b(n-2).
Особенность рекурсивного определения заключается в том, что оно позволяет с помощью конечного высказывания определить бесконечное множество объектов. Аналогично с помощью конечной рекурсивной записи алгоритма можно описать бесконечное вычисление, причем запись алгоритма не будет содержать организации явных повторений.
В общем виде рекурсивный алгоритм можно выразить как некоторый алгоритм P состоящий из комбинации последовательности действий S и самого P: P = P [S, P]. На каждом шаге n комбинация P [S, Pn-1] представляет элементарную задачу в предположении, что Pn-1 уже вычислено.
Решать задачу рекурсивно – это значит разложить ее на подзадачи, которые затем аналогичным образом (т.е. рекурсивно) разбить на еще меньшие подзадачи. На определенном уровне подзадачи становятся настолько простыми, что могут быть решены тривиально. Когда решены все элементарные подзадачи, тогда подзадачи составленные из элементарных тоже будут выполнены. Исходная задача окажется выполненной, когда будут выполнены все подзадачи ее образующие. Как правило, алгоритм разбиения исходной задачи на подзадачи записывается в виде рекуррентного соотношения.
Например: нахождение ma=max (a1...an) можно разбить на элементарные подзадачи в виде следующего рекуррентного соотношения
max (a1...an) = max (max (a1...an-1), an),
max (a1...an-1) = max (max (a1...an-2), an-1),…
Каждая элементарная подзадача решается выбором if x>y then ma=x else ma=y. На последнем уровне окажется тривиальная задача ma = max (a1) = a1, после чего находится ma = max (ma, a2) и т.д.
Подзадачи, на которые разбивается исходная задача, могут быть зависимыми и независимыми. Подзадачи независимы, когда они не пересекаются, т.е. не имеют общих одинаковых под-подзадач.
Деление задачи на независимые подзадачи лежит в основе стратегии «разделяй и властвуй», которая заключается в следующем:
Задача разбивается на независимые подзадачи (части) меньшей сложности (размерности).
Каждая подзадача решается отдельно.
Из отдельных решений подзадач строится решение исходной задачи используя рекуррентное соотношение.
Эффективность алгоритма при этом повышается существенно, если на каждом шаге разбиение производится на части приблизительно одинаковой размерности.
Заметим, что если подзадачи зависимы, т.е. имеют общие под-подзадачи, то метод "разделяй и властвуй" делает лишнюю работу, решая некоторые подзадачи по нескольку раз, увеличивая тем самым трудоемкость алгоритма, как показано ниже при рекурсивной реализации вычисления чисел Фиббоначи.
Стратегия динамического программирования эффективно реализует разбиение исходной задачи к зависимым подзадачам и заключается в следующем:
задача погружается в семейство задач той же природы (другими словами, разбивается на зависимые (могут пересекаться) подзадачи);
каждая подзадача решается отдельно один раз и необходимые значения решений подзадач запоминаются, что позволяет не решать снова уже встречавшиеся ранее подзадачи;
для исходной задачи строится возвратное рекуррентное соотношение, связывающее между собой необходимые значения решений зависимых подзадач.
Стратегия метода динамического программирования это попытка свести рассматриваемую задачу к более простым, однако зависимым задачам и опираясь на полученные и сохраненные в массиве результаты решения более простых, решить и исходную задачу. Эта стратегия за счет увеличения затрат памяти позволяет избавиться от повторного решения пересекающихся подзадач.