- •Процедуры и функции
- •Процедуры
- •Пример Вызов процедуры InpInt для ввода k целых чисел в массив m.
- •Функции
- •Формальные и фактические параметры
- •Параметры-значения Параметры-значения передаются основной программой в подпрограмму через стек в виде их копий. Сам параметр программы подпрограммой измениться не может.
- •Параметры-переменные
- •Этот вариант лучше предыдущего, так как в стеке не создается копия исходного массива, что улучшает быстродействие и экономит память.
- •Локализация имен
- •Пример Структура вложенной программы.
- •Основное правило Паскаля
- •Допустимые вызовы процедуры
- •Совместимость и преобразование типов данных
- •Параметры-массивы и строки открытого типа
- •Процедурные типы
- •Проблема совместимости
- •Рекурсия
- •Побочный эффект
- •Рекурсивная функция
- •Стеки для локальных переменных и параметров
- •Реализация стеков параметров в Паскале
Рекурсивная функция
Определение Рекурсивные функции – функции, значения которых для данного аргумента, вычисляются с помощью значения для предшествующих аргументов.
Итеративное – повторяющееся действие.
Пример Умножение M*N.
Компьютер умножает на 1 и складывает и только!! Предположим, что необходимо выполнить на этом компьютере умножение 6*3.
Эта задача может быть разделена на две:
-
задача 6*2;
-
прибавить 6 к результату 1 задачи.
Вторую задачу можно выполнить. Первую задачу разделим на две:
-
умножить 6*1;
-
прибавить к результату задачи 1.1.
Названные действия представим в виде:
Multiply: =M + Multiply (M, N-1) - рекурсивный шаг.
умножение M*(N-1)
сложение M с результатом предыдущей задачи
Если N=1, то Multiply : = M - конечный шаг.
Построим рекурсивную функцию.
function Multiply (M, N: integer): integer;
{Умножение выполняется с помощью оператора +.
Предусловие: M и N определены и N>0
Постусловие: возвращение M+N}
begin
if N=1 then
Multiply: = M {конечный шаг}
else Multiply: = M + Multiply (M, N-1) {рекурсивный шаг}
end;
Трассировка рекурсивной функции
Пусть в программе есть вызов Multiply (6, 3);
Определение Запись активации – прием, позволяющий проследить значения параметров при каждом вызове и составить общую картину выполнения функции.
При вызове функции Multiply M=6, N имеет значения 3, 2 и 1.
Свойства рекурсивных задач и решений
-
В задаче можно выделить один или больше конечных шагов, имеющих простое, не рекурсивное решение.
-
Все прочие шаги задачи могут быть разделены на задачи (с помощью рекурсии), которые приближаются к конечным шагом.
-
В конце концов вся задача может быть сведена таким образом только к конечным шагом, имеющим сравнительно простое решение.
Последовательность действий для решения задачи
-
Вникнуть в задачу.
-
Определить в задаче конечные цели.
-
Определить в задаче рекурсивные цели.
Обычно рекурсивные алгоритмы содержат оператор if, имеющий следующую форму.
if достигнут конечный шаг
then
этот шаг выполняется
else
задача с помощью рекурсии делится на более простые подзадачи.
Пример Multiply (5,4)
Умножить(5*4) Умножить (5*3) Умножить (5*2) Умножить (5*1) |
|
добавить 5 добавить 5 добавить 5 |
к (5*3) к (5*2) к (5*1) |
Рекурсивная процедура
procedure Reverse (N: integer);
{выводит строку длиной N в порядке, обратном тому, в котором эта строка вводилась.
Предусловие: N больше или равно единице.
Постусловие: выводит N символов}
var
next: char; {следующий символ}
begin
if N=1 then
begin {конечный шаг}
read (next);
write (next)
end
else
begin {рекурсия}
Read (next)
Reverse (N-1)
Write (next)
end
end;
Трассировка выполнения оператора REVERSE (3)
Значение N передается в процедуру при её вызове, так как N – её параметр.
Значение Next первоначально не определено, так как Next – локальная переменная.
Рекурсивный спуск завершается и начинается рекурсивный возврат, когда условие завершения становится истинным.
Последовательность действий для рекурсивного вызова Reverse (3)
Действия из одной записи активации представлены с одинаковым отступом.
Вызов Reverse со значением N, равным 3.
Считывание в NEXT первой буквы a.
Вызов Reverse со значением N, равным 2.
Считывание в NEXT второй буквы b
Вызов Reverse со значением N, равным 1.
Считывание в NEXT третьей буквы c.
Вывод третьей буквы c.
Возврат из третьего вызова.
Вывод второй буквы b.
Возврат из второго вызова.
Вывод первой буква a.
Возврат из первого вызова.