- •64 Жегуло а.И. Компьютерные науки 2-й семестр 2011-2012 гг. Компьютерные науки Лекции для студентов 1 курса мехмата, 2011-2012 уч. Г.
- •2 Семестр
- •16.Модули
- •16.1.Модуль и модульное программирование
- •16.2.Структура модуля
- •Interface //Раздел интерфейса
- •Implementation //Раздел реализации
- •Initialization //Раздел инициализации
- •Пример модуля и его использования
- •Interface //Раздел интерфейса
- •Implementation //Раздел реализации
- •Заголовок модуля
- •Раздел интерфейса interface
- •Раздел реализации implementation
- •Раздел инициализации initialization
- •16.4.Использование объявленных в модуле объектов
- •17.Файлы
- •17.1.Файлы. Классификация файлов
- •17.2.Организация работы с файлами
- •17.3.Подпрограммы для работы с файлами любых типов Связывание файловой переменной с файлом
- •Запись в файл
- •17.5.Обработка ошибок ввода-вывода
- •17.6.Текстовые файлы
- •17.6.1.Структура текстового файла
- •17.6.2.Особенности открытия текстовых файлов
- •17.6.3.Особенности чтения и записи для текстовых файлов
- •17.6.7.Поэлементная обработка текстовых файлов, состоящих из строковых значений и чисел
- •17.7.Типизированные файлы
- •17.7.1.Описание и структура типизированного файла
- •17.7.5.Сравнение текстовых и типизированных файлов
- •17.7.6.Пример работы с типизированными файлами из записей
- •18.Процедурные типы
- •18.1.Назначение процедурных типов
- •18.2.Описание процедурных типов и процедурных переменных
- •18.3.Присваивание процедурным переменным. Вызов подпрограмм через процедурные переменные
- •18.4.Процедурные переменные в качестве параметров
- •19.Рекурсия
- •19.1.Что такое рекурсия
- •19.2.Рекурсивные подпрограммы
- •19.3.Прямая и косвенная рекурсия
- •19.4.Предварительное (опережающее) описание подпрограммы
- •19.5.Опасности рекурсии
- •19.5.1.Бесконечная рекурсия
- •19.5.2.Глубокая рекурсия
- •19.5.3.Итерация и рекурсия, необоснованное применение рекурсии
- •19.6.Когда использовать рекурсию
- •19.7.Формы рекурсивных подпрограмм
- •19.8.Примеры рекурсивных программ
- •19.8.1.Вывод цифр целого числа в прямом порядке
- •19.8.2.Поиск максимального элемента массива
- •19.9.Задача о Ханойских башнях
- •20.Указатели
- •20.1.Указательные типы
- •Описание типизированного указателя
- •20.2.Операции с указателями
- •20.3.Примеры присваивания для указателей
- •20.4.Статические и динамические переменные
- •Создание новой динамической переменной базового типа и установка на нее указателя
- •Уничтожение динамической переменной, на которую ссылается указатель
- •Проблема потерянных ссылок
- •21.Динамические структуры данных
- •21.1.Данные статической структуры и данные динамической структуры
- •21.2.Односвязные линейные списки
- •21.2.1.Структура односвязного линейного списка
- •Вставка элемента после заданного элемента
- •21.3.Стеки
- •21.3.1.Реализация стека через односвязный линейный список
- •21.3.2.Применение стеков
- •21.3.3.Реализация стека на основе массива
- •21.4.Деревья
- •21.4.1.Основные определения
- •Алгоритм построения идеально сбалансированного дерева
- •21.4.3.Способы обхода дерева
- •Деревья поиска
- •Построение дерева поиска
19.5.2.Глубокая рекурсия
Если алгоритм достигает слишком большой глубины рекурсии, он может привести к переполнению стека подпрограмм. Минимизировать использование стека можно за счет уменьшения числа определяемых в подпрограмме переменных, использования глобальных переменных..
Если стек все равно переполняется, перепишите алгоритм в не рекурсивном виде.
19.5.3.Итерация и рекурсия, необоснованное применение рекурсии
Итерация – это организация обработки данных с помощью циклов.
Пример: Вычислим число Фибоначчи с заданным номером с помощью цикла и рекурсивно.
f0=f1=1; fn=fn-1+fn-2 при n>1
Итерационный вариант |
Рекурсивный вариант |
function Fib(n:integer): integer; var i,f1,f2,f3: integer; begin if (n=1) or (n=2) then Fib:=1 else begin f1:=1; f2:=1; for i:=3 to n do begin f3:=f1+f2; f1:=f2; f2:=f3 end Fib:=f3 end; end; |
function RF(n:integer):integer; begin if (n=1) or (n=2) then RF:=1 else RF:=RF(n-1)+RF(n-2) end; |
Вычислим рекурсивно 5-ое число Фибоначчи.
Сколько рекурсивных вызовов произойдет?
Для вычисления 4-го числа надо вычислить 3-ое и 2-е, для вычисления 3-го – 2-ое и 1-ое, затем повторно вычислить 2-ое; наконец, повторно вычислить 3-е, 2-ое и 1-ое. Каждый вызов при n>1 приводит к двум дальнейшим вызовам, т.е. число вызовов растет экспоненциально. Всего будет 8 рекурсивных вызовов. Кроме того, заново вычисляются числа Фибоначчи, которые уже были вычислены. |
|
Вывод: рекурсивная программа вычисления чисел Фибоначчи непригодна для практического использования.
19.6.Когда использовать рекурсию
Рекурсия полезна при решении задач, которые естественным образом разбиваются на несколько подзадач, каждая из которых является более простым случаем исходной задачи. Но даже если задача определена рекурсивно, не всегда лучшим способом решения задачи является рекурсивный алгоритм. Во многих случаях вместо краткого рекурсивного алгоритма лучше воспользоваться циклом. Хотя программа станет длиннее, работать она будет быстрее.
19.7.Формы рекурсивных подпрограмм
В общем случае любая рекурсивная подпрограмма P включает в себя некоторое множество операторов S и один или несколько условных операторов рекурсивного вызова P. Пока условие истинно, рекурсивный спуск продолжается. Когда условие становится ложным, спуск заканчивается и начинается рекурсивный возврат из всех вызванных на данный момент копий рекурсивной подпрограммы.
Рассмотрим четыре разные формы рекурсивных подпрограмм на примере процедур (для функций аналогично):
Действия выполняются до рекурсивного вызова (на рекурсивном спуске).
procedure P(n); begin S; //выполняется на рекурсивном спуске if условие then Р(n-1) end;
Действия выполняются после рекурсивного вызова (на рекурсивном возврате).
procedure P(n); begin if условие then P(n-1); S; //выполняется на рекурсивном возврате end;
Действия выполняются до и после рекурсивного вызова (на рекурсивном спуске и на рекурсивном возврате).
procedure P(n);
begin
S1; //выполняется на рекурсивном спуске;
if условие then P(n-1);
S2; //выполняется на рекурсивном возврате
end;
procedure P(n);
begin
if условие then
begin
S1; //выполняется на рекурсивном спуске
P(n-1);
S2 //выполняется на рекурсивном возврате
end
end.
Каскадная рекурсия – рекурсивные вызовы образуют дерево, например, при рекурсивном вычислении чисел Фибоначчи, при обходе деревьев.
procedure P(n); begin S; //может отсутствовать if условие1 then P(n-1); S1; //может отсутствовать if условие2 then P(n-1); S2 //может отсутствовать
end;