Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование. Процедурное программирование. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
Основные возможности процедурного программирования по работе с числовыми данными
На основании пузырьковой сортировки разработан один из самых
эффективных алгоритмов сортировки – быстрая сортировка (автор Чарльз Хоар) с вычислительной сложностью O(N*logN). Основание логарифма в формуле опущено, так как логарифмы по разным основаниям отличаются константным множителем, который уже входит в понятие «O» большого. Этот метод сортировки представлен в рекурсивном виде и подробно рас­смотрен в п. 1.4.
Сортировка слиянием: набор разделяется на несколько кратных
частей, каждая сортируется отдельно, затем эти упорядоченные наборы соединяются в один. Например, в случае двух наборов объединение происходит следующим образом: выбирается и помещается первым наименьший элемент из двух наборов (для этого необходимо сравнить наименьшие элементы из обоих наборов), далее процедура продолжает­ся, пока все элементы не будут объединены. Вычислительная сложность: O(N*logN).
Числовые наборы, используемые в программе, можно получать раз-
личными способами: генерируя набор с использованием датчика случай­ных чисел, организуя ввод с клавиатуры либо читая их из другого источ­ника (например, текстового файла).
Пример программы № 3
При помощи датчика случайных чисел создать квадратную мат-
рицу, упорядочить строки матрицы в порядке увеличения суммы эле­ментов в них.
Разработка программы
Для хранения матрицы нам потребуется двумерный массив. Объявим
этот тип данных, назовем его TMatrix, и константу N, содержащую поря­док матрицы. Объявим переменную-массив M для хранения матрицы и индексные переменные I и J для организации обращения к ее элементам, остальные переменные будем добавлять по мере необходимости.
const N = 4; type TMatrix = array[1..N, 1..N] of Integer; var M: TMatrix; I, J: Integer;
По заданию требуется, чтобы матрица содержала случайные целые
числа. Для того чтобы получить случайные значения, воспользуемся стан-
31
Глава 1
дартным оператором Random и последовательно в двойном цикле запол­ним массив.
Random(Limit);
Возвращает случайное значение из диапазона [0 ... Limit – 1].
Оператор Random может использовать вспомогательный оператор
Randomize, который инициализирует алгоритм генерации случайных чисел.
Randomize; for I := 1 to N do for J := 1 to N do M[I, J] := Random(100);
Выведем полученную матрицу на экран: для этого организуем циклы
по строкам и столбцам матрицы, считая, что первый индекс массива (пере­менная I) соответствует номеру строки матрицы, а второй (переменная J) – номеру столбца. Для обеспечения «красивого» вывода данных можно форматировать вывод, отводя на каждое число заранее определенное ко­личество позиций, которое указывается через двоеточие после имени пе­ременной. Будем выводить элементы одной строки матрицы последова­тельно, выделяя по 3 позиции на каждый элемент, а при переходе к новой строке матрицы будем делать перевод строки.
WriteLn('Матрица'); for I := 1 to N do begin for J := 1 to N do Write(M[I, J]:3); WriteLn; end;
Далее по заданию требуется упорядочить строки матрицы по сумме
элементов, содержащихся в них. Воспользуемся сортировкой методом вы­бора. Общая схема алгоритма, как приведено выше, следующая: нужно по очереди искать и помещать на свои места сначала первую строку, содер­жащую минимальную сумму из всех строк, затем вторую, содержащую минимальную сумму из оставшихся строк, и т. д. Реализуется алгоритм с использованием вложенных циклов, с внешним циклом по номеру стро­ки, поиск которой производится. Алгоритм несколько осложняется тем, что сравниваются не пары элементов, а суммы по строкам, которые необ­ходимо предварительно вычислить, а также тем, что для обмена строк мес-
32
Основные возможности процедурного программирования по работе с числовыми данными
тами необходимо попарно обменять местами все элементы этих строк, на­ходящиеся на соответствующих местах.
После упорядочения повторно выведем матрицу на экран. Текст программы полностью приведен в листинге 3.
Листинг 3. Пример программы № 3
program Example3;
{$APPTYPE CONSOLE}
uses SysUtils, Windows; const N = 4; type TMatrix = array[1..N, 1..N] of Integer; var M: TMatrix; I, J, K, Min, Min_Sum, Sum, T: Integer; begin SetConsoleOutputCP(1251); {Заполняем матрицу случайными числами.} Randomize; for I := 1 to N do for J := 1 to N do M[I, J] := Random(100); WriteLn('Матрица'); {Выводим матрицу на экран.} for I := 1 to N do begin for J := 1 to N do Write(M[I, J]:3); WriteLn; end; {Упорядочиваем строки матрицы методом выбора.} for I := 1 to N - 1 do begin Min := I; {Вычисляем сумму I-й строки и принимаем ее за первоначальный минимум.} Min_Sum := 0; for J := 1 to N do Min_Sum := Min_Sum + M[I, J]; {Просматривая строки с номерами большими I, отыскиваем минимум.} for J := I + 1 to N do begin Sum := 0; for K := 1 to N do Sum := Sum + M[J, K];
33
Глава 1
if Min_Sum > Sum then begin Min_Sum := Sum; Min := J; end; end; {Если найденная строка отлична от I-й, меняем их местами.} if Min <> I then begin for J := 1 to N do begin T := M[I, J]; M[I, J] := M[Min, J]; M[Min, J] := T; end; end; end; { Выводим результирующую матрицу на экран. } WriteLn('Упорядоченная матрица'); for I := 1 to N do begin for J := 1 to N do Write(M[I, J]:3); WriteLn; end; ReadLn; end.
Результат работы программы
Матрица 63 38 46 55 56 15 4 84 35 20 6 77 9 12 19 24 Упорядоченная матрица 9 12 19 24 35 20 6 77 56 15 4 84 63 38 46 55
Контрольные вопросы и задания
1. Назовите операторы для генерации случайных чисел.
2. Каким образом сгенерировать набор случайных значений так, что-
бы среди них были как положительные, так и отрицательные величины? Как целые, так и вещественные?
34
Основные возможности процедурного программирования по работе с числовыми данными
3. Приведите несколько простейших алгоритмов сортировки. Укажи-
те их вычислительную сложность.
4. Напишите код, заполняющий матрицу таким образом, чтобы на
элементы главной диагонали принимали значения 2, на двух соседних диа­гоналях – 1, а остальные элементы матрицы были равны 0.
5. Как объявить трехмерный массив и работать с ним?
1.4. Основные инструменты структурного программирования. Процедурные типы. Рекуррентность и рекурсия. Реализация в языке
Процедуры и функции
При конструировании достаточно сложного алгоритма логично раз-
бить его на ряд более простых задач. В этом случае в основном алгоритме предполагается обращение к вспомогательным алгоритмам, позволяю­щим решать более простые подзадачи. При реализации таких вспомога­тельных алгоритмов на языке Delphi их оформляют в виде подпрограмм, которые в Delphi представлены в виде процедур и функций. Подпрограм­мы, в свою очередь, могут разбиваться на более мелкие подпрограммы нижнего уровня.
Подпрограмма представляет собой относительно самостоятельный
фрагмент программы, оформленный особым образом и снабженный име­нем. По структуре (используемым разделам) подпрограмма может напо­минать программу. В ней могут быть собственные переменные, собствен­ные описания типов и даже собственные функции и процедуры.
Процедуры и функции в программе оформляют в виде отдельных
блоков, каждый из которых начинается ключевым словом (procedure или function). Эти блоки располагаются в программе перед оператором begin, начинающим основное тело программы.
Описать подпрограмму – это значит указать ее заголовок и тело.
В заголовке объявляются имя подпрограммы и формальные параметры, если они есть. Формальными параметры называются потому, что они служат для представления логики подпрограммы и не несут конкретных значений. Для функции, кроме того, указывается тип возвращаемого ею результата.
Отличие функции от процедуры обычно заключается в том, что ре-
зультатом исполнения операторов, образующих тело функции, всегда яв­ляется некоторое единственное значение, поэтому вызов функции можно использовать в выражениях наряду с переменными и константами.
35
Глава 1
Общая форма записи заголовка подпрограммы:
function <имя> [(<список формальных параметров>)]: <тип результата>; procedure <имя> [(список формальных параметров)];
<Имя> – правильный идентификатор. <Список формальных параметров> включает в себя параметры дан-
ной подпрограммы, и если в списке формальных параметров нет необхо­димости, то он может отсутствовать. Если же он есть, то в нем должны быть перечислены имена формальных параметров и их типы.
<Тип результата> – тип значения, получаемого после выполнения
функции.
Примеры заголовков подпрограмм
function ArcTan(Phi : Real) : Real; procedure Output;
За заголовком следует тело подпрограммы, которое, подобно про-
грамме, состоит из раздела описаний и раздела исполняемых операторов. В разделе описания подпрограммы могут встретиться описания подпро­грамм низшего уровня, в которых могут быть описания других подпро­грамм, и т. д.
Все объекты, объявленные внутри подпрограммы (типы, константы,
переменные, процедуры и функции), являются локальными по отношению к подпрограмме и невидимы снаружи подпрограммы. При входе в подпро­грамму становятся доступными объявленные в ней имена, но при этом со­храняется доступ ко всем именам, описанным выше по тексту программы до описания данной подпрограммы. Эти объекты называются глобальными по отношению к подпрограмме. Имена локальных объектов могут совпа­дать с именами глобальных объектов, в этом случае локальное имя «за­крывает» глобальное.
Любой из формальных параметров подпрограммы может быть одним
из нескольких видов: параметром-значением, параметром-переменной,
параметром-константой, выходным параметром, параметром процедур­ного типа. В данном учебном пособии будут использоваться только пер-
вые два вида параметров.
Если параметр определен как параметр-значение, то перед вызовом
подпрограммы его фактическое значение копируется во временную память и передается подпрограмме. Поэтому любые возможные изменения в под­программе параметра-значения никак не отразятся на значении фактиче-
36
Основные возможности процедурного программирования по работе с числовыми данными
ского параметра. При вызове подпрограммы параметру-значению могут соответствовать как переменная, так и произвольное выражение и даже константа.
Если параметр определен как параметр-переменная, то при вызове
подпрограмме передается сама переменная, а не ее копия (фактически в этом случае подпрограмме передается адрес переменной). Изменение па­раметра-переменной приводит к изменению самого фактического парамет­ра в вызывающей программе. При описании перед формальным парамет­ром-переменной необходимо ставить зарезервированное слово var. При вызове подпрограммы параметру-переменной должен соответствовать фактический параметр в виде переменной нужного типа.
Упоминание имени подпрограммы в тексте программы называется
вызовом этой подпрограммы. Необходимо помнить, что при вызове под­программы имена фактических параметров (которые замещают формаль­ные параметры) могут как отличаться от имен соответствующих формаль­ных параметров, так и совпадать с ними, но при этом их количество, вза­имный порядок и тип должны быть четко соблюдены.
В отличие от процедуры, где выходное значение присваивается вы-
ходному параметру, в функции выходное значение должно быть присвоено имени функции или обобщенной переменной Result.
Компиляцией подпрограмм можно управлять с помощью специаль-
ных директив, которые указываются либо после заголовка подпрограммы (локальный вариант, действует только для указанной подпрограммы), ли­бо в специальном оформлении директивы (в фигурных скобках, в кото­рых первым стоит символ доллара ($)). В этом случае директива действу­ет на все подпрограммы в программе, пока не будет отменена другой ди­рективой (блоковый вариант). Одним из примером такого управления является построение косвенной рекурсии с использованием директивы forward.
Пример программы № 4
С клавиатуры вводятся координаты вершин двух треугольников.
Необходимо сравнить площади введенных треугольников.
Приведем три варианта решения.
Вариант № 1. Процедура без параметров В листинге 4.1 приведен пример процедуры Square1, использующей
для вычисления глобальные переменные: A, B, C – длины сторон тре­угольника и S – вычисленная площадь. Переменная P является локальной.
В этом примере все взаимодействие процедуры осуществляется че-
рез глобальные переменные: перед вызовом Square1 необходимо присво-
37
Глава 1
ить переменным A, B и C необходимые значения, а после работы процеду­ры площадь вычисленного треугольника оказывается в переменной S.
Листинг 4.1. Первый вариант программы сравнения
площадей треугольников
program Example4_1;
{$APPTYPE CONSOLE}
uses SysUtils, Windows; var AB1, AC1, BC1, AB2, AC2, BC2 : Real; S1, S2 : Real; A, B, C, S: Real; // Процедура Square без параметров
procedure Square1; var P: Real; begin
// Для вычисления используются глобальные переменные: P := (A + B + C)/2; S := Sqrt(P*(P-A)*(P-B)*(P-C));
end; begin
SetConsoleOutputCP(1251); WriteLn('Введите стороны треугольника №1: '); ReadLn(AB1, AC1, BC1); WriteLn('Введите стороны треугольника №2: '); ReadLn(AB2, AC2, BC2); // Присваивание значений глобальных переменных: A := AB1; B:= BC1; C := AC1; Square1; // Вызов процедуры для треугольника №1 S1:= S; // Сохранение площади треугольника №1 // Присваивание значений глобальных переменных: A := AB2; B:= BC2; C := AC2; Square1; // Вызов процедуры для треугольника №2 S2:= S; // Сохранение площади треугольника №2 if S1 > S2 then WriteLn('Площадь треугольника №1 больше') else WriteLn('Площадь треугольника №2 больше'); ReadLn; end.
Этот способ использования процедур не только неудобен из-за
большого числа операторов присваивания, которые до обращения к проце­дуре определяют значения переменных A, B и C, но и не поощряется, так
38
Основные возможности процедурного программирования по работе с числовыми данными
как работает с глобальными переменными и не способствует коллективной разработке программ. Излишняя зависимость кода подпрограмм от гло­бальных объектов может привести к появлению трудновыявляемых оши­бок времени выполнения программы.
Вариант № 2. Процедура с параметрами В листинге 4.2 приведен второй вариант программы, использующей
для вычисления площади процедуру Square2, имеющую формальные па­раметры. Это позволяет избавиться в программе от лишних переменных и лишних операторов присваивания.
Переменные, указанные в скобках (A, B, C, S), – это формальные па-
раметры. При выполнении программы в момент обращения к процедуре они заменяются фактическими параметрами: первый формальный пара­метр заменяется первым фактическим параметром, второй формальный параметр – вторым фактическим и т. д.
В примере A, B, C – это формальные параметры-значения, а S – это
формальный параметр-переменная.
Листинг 4.2. Второй вариант программы сравнения
площадей треугольников
program Example4_2;
{$APPTYPE CONSOLE}
uses SysUtils, Windows; var AB1, AC1, BC1, AB2, AC2, BC2 : Real; S1, S2 : Real; // Процедура Square2 с параметрами
procedure Square2(A, B, C: Real; var S: Real); var P: Real; begin
// Для вычисления используются глобальные переменные: P := (A + B + C)/2; S := Sqrt(P*(P-A)*(P-B)*(P-C));
end; begin
SetConsoleOutputCP(1251); WriteLn('Введите стороны треугольника №1: '); ReadLn(AB1, AC1, BC1); WriteLn('Введите стороны треугольника №2: '); ReadLn(AB2, AC2, BC2); // Вызов процедуры для треугольника №1: Square2(AB1, AC1, BC1, S1); // Вызов процедуры для треугольника №2
39
Глава 1
Square2(AB2, AC2, BC2, S2); if S1 > S2 then WriteLn('Площадь треугольника №1 больше') else WriteLn('Площадь треугольника №2 больше'); WriteLn(S1, ' ', S2); ReadLn; end.
Вариант № 3. Использование функции В листинге 4.3 приведен пример программы, использующей функ-
цию Square3 для вычисления площади треугольника. Функция возвращает значение в точку вызова, поэтому вызов функции возможен непосредст­венно в условном операторе. Каждая функция имеет зарезервированную переменную Result, которой присваивается результат функции.
Листинг 4.3. Третий вариант программы сравнения площадей
треугольников
program Example4_3;
{$APPTYPE CONSOLE}
uses SysUtils, Windows; var AB1, AC1, BC1, AB2, AC2, BC2 : Real;
function Square3(A, B, C: Real) : Real; var P: Real; begin
P := (A + B + C)/2; Result := Sqrt(P*(P-A)*(P-B)*(P-C));
end; begin
SetConsoleOutputCP(1251); WriteLn('Введите стороны треугольника №1: '); ReadLn(AB1, AC1, BC1); WriteLn('Введите стороны треугольника №2: '); ReadLn(AB2, AC2, BC2); if Square3(AB1, AC1, BC1) > Square3(AB2, AC2, BC2) then WriteLn('Площадь треугольника №1 больше') else WriteLn('Площадь треугольника №2 больше'); WriteLn(S1, ' ', S2); ReadLn; end.
40
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]