
- •Языки и системы программирования Алгоритмы
- •Языки программирования
- •Область применения языков программирования
- •Сложность и эффективность языков программирования
- •Трансляторы
- •Характеристика с/п Pascal abc
- •Используемые в с/п Pascal abc «горячие клавиши»
- •Структура программы на Паскале
- •Сообщения об ошибках. Отладка программы.
- •Система подсказок.
- •Команды вывода данных на экран
- •Константы
- •Переменные
- •Арифметические выражения. Приоритет арифметических операций
- •Стандартные арифметические функции
- •Процедуры инкремента и декремента
- •Примеры решения линейных задач
- •Ввод данных с клавиатуры
- •Примеры решения диалоговых задач
- •Линейные задачи для самостоятельной работы
- •Лаб. 1. Линеаризовать выражение:
- •Лаб. 2. Линейные диалоговые задачи (на одно действие)
- •Лаб. 3. Диалоговые задачи на несколько действий
- •Ветвление
- •Логические выражения
- •Вложенное ветвление
- •Лаб. 4. Задачи на ветвление:
- •Лаб. 5. Задачи на ветвление с вычислениями:
- •Выбор варианта
- •Лаб. 6. Задачи на выбор варианта:
- •Как выбрать цикл?
- •Экстренные события в теле цикла
- •Лаб. 7. Числовые задачи с циклом For
- •Лаб. 8. Сюжетные задачи с циклом For
- •Лаб. 9. Задачи с условными циклами
- •Библиотека crt
- •Библиотека sounds
- •Лаб. 10. Задачи с использованием циклов и библиотек crt и sounds
- •Порядковые типы данных
- •Перечислимый тип данных
- •Символьный тип данных
- •Ограниченный (интервальный) тип данных
- •Лаб. 11. Задачи со строками
- •Массивы
- •Решение задач с массивами
- •Поиск минимального (максимального) элемента массива
- •Сортировка массива.
- •Двумерные и многомерные массивы
- •Лаб. 12. Задачи с одномерными массивами
- •Лаб. 13. Задачи с двумерными массивами
- •Множества
- •Файлы данных
- •Записи и базы данных
- •Библиотека GraphAbc
- •Действия с графическим окном:
- •Точечная графика
- •Графические примитивы
- •Текст в графическом окне
- •Использование готовых точечных рисунков
- •Вспомогательные алгоритмы
- •Рекурсия
- •Событийное программирование
- •Использование таймеров
- •Использование сторонней библиотеки ukeyb
Рекурсия
Встречаются задачи, в которых подпрограмма вызывает саму себя. Это называется рекурсией. Таким образом можно организовать хитрые циклы, которые иным способом либо очень трудно, либо невозможно сделать. Например, процедура KRUG рисует круг, состоящий из кругов, которые в свою очередь состоят из кругов и т.д… Ёлочка – это большая ветка, состоящая из веток, которые состоят из веточек… Любые самоповторяющиеся рисунки (фракталы) создаются с помощью рекурсии. Но не только рисунки. С помощью рекурсии работает процедура закраски (в начальной позиции ставится точка, которая ставит точки вокруг себя, а те в свою очередь ставят точки вокруг них… и т.д., пока не будет достигнута граница). С помощью рекурсии можно найти кратчайший путь к выходу из лабиринта, экономно раскроить заготовку на детали и т.д. Одним словом, если встречается сложная задача, которую вроде бы решить нужно циклом, но непонятно, как его организовать – попробуйте рекурсию! Приведём пример:
Нарисовать с использованием рекурсии ёлочку.
program
elka;
uses
graphabc; var
gd,gm:integer;
procedure
vetka(x,y,alf,dl:real); var
xk,yk,dx,dy:real;
i:integer; begin
xk:=x+dl*sin(alf);
yk:=y-dl*cos(alf);
line(round(x),round(y),round(xk),round(yk));
if
dl<15
then
exit;
{Условие
окончания рекурсии}
dx:=(xk-x)/8;
dy:=(yk-y)/8;
for
i:=1 to
8 do
begin
vetka(x+i*dx,y+i*dy,alf-pi*0.35,dl*(0.5-i*0.06));
vetka(x+i*dx,y+i*dy,alf+pi*0.35,dl*(0.5-i*0.06));
end;
end; begin
setwindowsize(700,500);
vetka(320,450,0,400);
end.
Находим координаты (xk, yk) конца веточки и проводим отрезок из начала в конец. Затем делим ветку на 8 частей (находим шаги dx и dy) и в этих точках рекурсивно вызываем процедуру «ветка», задавая ей другие углы (влево и вправо от ветки на π*0.35) и уменьшенную длину.
Должно получиться нечто следующее:
Использование рекурсии опасно зависанием. В примере с ёлочкой каждая следующая веточка вызывается меньших размеров. Но так может продолжаться до бесконечности (а точнее, до переполнения памяти), если процесс уменьшения не остановить. В данном примере мы прекращаем рекурсивный вызов, если длина очередной веточки становится меньше 15 пикселов. (Можно сделать ограничение в 1 пиксел, но тогда иголки будут короткими). На этом примере можно сформулировать правило безопасной рекурсии: В рекурсивной процедуре проверку условия окончания рекурсии нужно выполнять ДО рекурсивного вызова.
Кроме прямой рекурсии, о которой рассказано выше, существует ещё косвенная рекурсия: подпрограмма A вызывает подпрограмму B, которая в свою очередь вызывает A … Например, круг, который состоит из квадратов, которые состоят из кругов… Здесь возникает такая проблема: одна из этих подпрограмм, например, A, описана выше и не знает о существовании подпрограммы B, которая описана ниже, следовательно, не может к ней обратиться. Для решения такой проблемы в Паскале предусмотрен механизм предварительного описания. Заголовок (только!) подпрограммы B копируют до подпрограммы A, а в конце этого заголовка после точки с запятой добавляют слово forward. Это слово показывает Паскалю, что это ещё не описание подпрограммы, а только прототип, предварительное оповещение.