Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Программирование. Процедурное программирование. Учебное пособие
.pdf
Основные возможности процедурного программирования по работе с числовыми данными
Указанный <список операторов> будет выполняться до тех пор, пока
<условие> не станет истинным. Основное отличие от цикла while состоит
в том, что гарантируется хотя бы одно выполнение действий до завершения цикла (так как проверка условия выполняется в конце каждого шага
цикла). В цикле repeat…until нет необходимости помещать операторы
в отдельные операторные скобки begin и end, так как ключевые слова
repeat и until уже выполняют их функцию.
Вычисление суммы последовательности чисел, заканчивающейся нулем
repeat
ReadLn(X);
Sum := Sum + X;
until X = 0
Оператор repeat…until является основным оператором цикла при
создании интерактивных программ (когда нужно организовать взаимодействие с пользователем).
Для гибкого управления операторами циклов for, while и repeat су-
ществуют следующие операторы:
1) break – реализует немедленный выход из цикла, при этом управ-
ление передается оператору, следующему после оператора цикла;
2) continue – обеспечивает досрочное завершение очередного шага
цикла и передает управление на следующий шаг цикла.
Одной из распространенных ошибок при написании программы яв-
ляется получение бесконечного цикла. Бесконечный цикл – это такой цикл,
который никогда не прекращается. Чаще всего он может возникнуть в циклах while и repeat…until из-за ошибок в логическом условии цикла.
Оператор множественного выбора
Условный оператор if...then....else позволяет программе выполнять
переходы по двум направлениям, определяемым значением логического
выражения (истина, ложь). Для использования ветвления по нескольким
направлениям можно использовать несколько последовательных или вложенных условных операторов. Однако язык Delphi предоставляет для этой
цели другую управляющую структуру (оператор множественного выбора
case), которая позволяет построить ветвление по многозначному условию
в более удобной форме.
Общая форма записи оператора множественного выбора
case <выражение> of
<значение1>: <оператор1>;
<значение2>: <оператор2>;
...
21

Глава 1
<значениеn>: <операторn>
else
<оператор>
end;
Вначале вычисляется значение <выражения>, которое должно быть
порядкового типа и играет роль селектора. Далее выполняется <оператор>,
соответствующий одному из указанных значений результата вычисления
<выражения>. В случае несоответствия значения выражения перечисленным значениям выполняется <оператор>, стоящий за словом else. Все
<значения> должны быть значениями того же типа, какой имеет выражение. Любой из операторов может быть составным.
Примеры операторов множественного выбора
// Определение четности числа
case X mod 2 of
0 : WriteLn('Число ', X , ' – четное');
1 : WriteLn('Число ', X , ' – нечетное');
end;
// Определение номера квартала по номеру месяцы
case Month of
1, 2, 3 : WriteLn('Первый квартал');
4, 5, 6 : WriteLn('Второй квартал');
7, 8, 9 : WriteLn('Третий квартал');
10, 11, 12 : WriteLn('Четвертый квартал');
end;
Пример программы № 2
С клавиатуры вводится последовательность целых положительных
чисел. Признаком окончания ввода служит ввод числа 0. Определить, является ли эта последовательность возрастающей. Если она целиком не
является возрастающей, то найти длину самой длинной возрастающей
подпоследовательности.
Пример
Ввод: 1 2 3 2 4 2 7 9 10 11 10 7 0
1 2 3 2 4 2 7 9 10 11 10 7 0
Подпосл. № 1
Длина 3
Подпосл. № 2
Длина 2
Подпосл. № 3
Длина 5
Выводы:
1. Последовательность невозрастающая.
2. Длина самой длинной возрастающей подпоследовательности равна 5.
22

Основные возможности процедурного программирования по работе с числовыми данными
Разработка программы
В программе необходимо реализовать ввод чисел до тех пор, пока не
будет введено число 0. Лучше всего это сделать при помощи цикла repeat
until. Дополнительно подсчитаем количество введенных значений в переменной N.
var
X, N: Integer;
begin
N := 0;
repeat
Read(X); // Вводим очередной член последовательности
// Обработка очередного члена последовательности
Inc(N); // Считаем количество введенных чисел
until X = 0;
end.
На каждой итерации цикла будет вводится очередное число последо-
вательности в переменную X. Как только будет введено число 0, цикл остановится.
Для того чтобы находить возрастающие подпоследовательности, не-
обходимо кроме очередного вводимого числа дополнительно помнить значение предыдущего введенного числа. Для этого воспользуемся переменной Y, в которой будем хранить значение предыдущего введенного числа.
var
X, Y, N: Integer;
begin
N := 1;
Read(Y); // Первое число вводим отдельно
repeat
Read(X); // Вводим очередной член последовательности
// Обработка очередного члена последовательности
Inc(N); // Считаем количество введенных чисел
Y := X; {Текущий член последовательности становится
предыдущим}
until X = 0;
end.
Далее нам понадобятся две дополнительные переменные:
Count – количество элементов из предшествующей подпоследова-
тельности, которые меньше очередного вводимого значения.
Max – длина наиболее длинной возрастающей подпоследователь-
ности.
23

Глава 1
Далее совершенствуем алгоритм обработки данных следующим об-
разом. Анализируем очередное введенное значение. Если это значение
больше предыдущего, то накапливаем количество возрастающих элементов в переменной Count, т. е. увеличиваем ее значение на единицу. Если же
очередное введенное значение будет меньше либо равно введенному до
него, то возрастающая подпоследовательность обрывается. В этом случае
ее длину надо сравнить с максимальной. Если длина очередной найденной
возрастающей подпоследовательности больше максимальной, то максимальное значение заменяем на это значение.
Сразу можно сделать проверку: если число возрастающих значений
равно общему числу значений, то последовательность является возрастающей.
var
X, Y, N, Count, Max: Integer;
begin
Read(Y); // Первое число вводим отдельно
Count := 1;
Max := 0;
repeat
Read(X); // Вводим очередной член последовательности
if X > Y then
begin
{Если очередной член последовательности больше
предыдущего, то увеличиваем длину текущей возрастающей
подпоследовательности на 1.}
Inc(Count);
end
else
begin
{Возрастание закончилось. Сравниваем длину найденной
возрастающей подпоследовательности с наибольшей, если она
больше
if Count > Max then
begin
Max := Count;
Count := 1;
end;
end;
Inc(N); // Считаем количество введенных чисел
Y := X; {Очередной член последовательности становится
предыдущим}
until X = 0;
if Max = N - 1 then
WriteLn('Последовательность является возрастающей')
else
, то присваиваем её значение наибольшей длине.}
24

Основные возможности процедурного программирования по работе с числовыми данными
WriteLn('Последовательность не является возрастающей');
if Max > 1
then
WriteLn('Длина возрастающей подпоследовательности ', Max);
else
WriteLn('Нет возрастающих подпоследовательностей');
end.
Далее определим границы возрастающей подпоследовательности.
В переменных X1 и X2 сохраним, с какого по какой члены последовательность являлась максимальной. Необходимо запоминать начало возрастающей подпоследовательности. Для этого нам понадобится еще переменная,
например Z. Вначале обнулим ее значение. Далее, как только последовательность начала возрастать, т. е. очередной член последовательности стал
больше предыдущего, запоминаем значение очередного члена последовательности в переменной Z. Но для того чтобы сохранить только первое
значение, применим условие: если значение Z нулевое, то это – первый
возрастающий элемент.
Как только последовательность перестала возрастать, обнулим зна-
чение Z. Но прежде чем делать обнуление, ее значение сохраним в переменной X1, а значение текущего члена подпоследовательности – в переменной X2. Однако делать это надо только в том случае, если длина новой
найденной возрастающей подпоследовательности больше предыдущих.
...
if X > Y then
begin
if Z = 0 then
Z := X;
Inc(Count);
end
else
begin
if Count > Max then
begin
Max := Count;
Count := 1;
X1 := Z;
X2 := Y;
end;
Z := 0;
end;
...
25

Глава 1
Текст программы полностью приведен в листинге 2.
Листинг 2. Пример программы № 2
program Example2;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
var
X, Y, Count, Max, N: Integer;
X1, X2, Z: Integer;
begin
SetConsoleOutputCP(1251);
N := 1;
Read(Y); // Первое число вводим отдельно
Count := 1;
Max := 0;
Z := Y;
repeat
Read(X); // Вводим очередной член последовательности
if X > Y then
begin
if Z = 0 then Z := X;
Inc(Count);
end
else
begin
if Count > Max then
begin
Max := Count;
Count := 1;
X1 := Z;
X2 := Y;
end;
Z := 0;
end;
Inc(N);
Y := X;
until X = 0;
if Max = N – 1 then
WriteLn('Последовательность является возрастающей')
else
WriteLn('Последовательность не является возрастающей');
if Max > 1 then
begin
WriteLn('Наиболее длинная возрастающая
подпоследовательность ', Max);
WriteLn('Начинается с ', X1,' по ', X2);
end
26

Основные возможности процедурного программирования по работе с числовыми данными
else
WriteLn('Последовательность не содержит возрастающих
подпоследовательностей');
ReadLn;
end.
Рис. 3. Результаты работы программы
Пример работы программы приведен на рис. 3.
Контрольные вопросы и задания
1. Для чего нужны идентификаторы? Какие требования предъявля-
ются к идентификаторам? Какие из перечисленных идентификаторов
(pi, do, symbol, 1X, y1, _length) являются правильными?
2. Перечислите структурные части программы. Каково назначение
каждой части?
3. Что такое оператор и какие виды операторов существуют?
4. Как работает условный оператор? Какие формы условного опера-
тора существуют?
5. Для чего предназначены операторы цикла? Какие их виды сущест-
вуют? В каком случае цикл не выполнится ни разу? В каком случае работа
цикла будет бесконечной?
1.3. Проектируемые типы для числовых данных.
Основные алгоритмы для работы с ними
Массивы
Во многих задачах разработки программного обеспечения возникает
необходимость обрабатывать наборы однотипных данных, будь то строки,
27

Глава 1
числа или, например, логические значения. Языки программирования высокого уровня содержат специальные, так называемые структурированные
типы данных, обеспечивающие хранение наборов величин, в общем случае однотипных и разнотипных, и доступ к ним, одним из представителей
которых является массив, содержащий однотипные (регулярные) данные.
В Delphi при помощи ключевого слова array можно объявить тип
данных – массив, позволяющий хранить индексированный набор значений.
Замечание. Термин «массив» может обозначать, во-первых, собирательное понятие типа данных, массив вообще, во-вторых, конкретный тип данных – массив с заданным диапазоном индексов
и типом элементов, определенный в программе, и, в-третьих, переменную-массив. Текущее значение термина следует определять из
контекста.
Пример объявления массива из 10 целых чисел
var
Numbers: array[1..10] of Integer;
В программе возможно обращение к каждому элементу массива по
его индексу (от 1 до 10, как указано в объявлении). Индекс передается
в квадратных скобках после имени переменной-массива.
Примеры обращения к элементам массива по индексу
Numbers[4] := 123;
WriteLn(Numbers[3]);
Индексированное обращение применимо для чтения и записи значе-
ний в массив.
В более общем виде позволительно объявлять многомерные масси-
вы, в которых каждая размерность может содержать свой диапазон индексов. Диапазон индексов может быть любым порядковым типом данных,
т. е. содержать конечное число значений, и не обязательно быть числовым
или строго положительным. Обращение к элементу массива требует указания стольких индексов, какова размерность массива. Сами элементы массива тоже могут принадлежать к любому другому типу данных, не обязательно целочисленному.
Зачастую значения верхних границ индексов выносят в нетипизиро-
ванные константы, это позволяет улучшить читаемость кода и при необходимости изменять границы массива во всем коде программы изменением
28

Основные возможности процедурного программирования по работе с числовыми данными
одной константы. Доступ к элементам массива в большинстве случаев организуется при помощи циклов, в которых границы индексов массива используются в качестве границ диапазона изменения переменной цикла.
Тип данных массив относится к данным, тип которых определяет
пользователь. Определение пользовательского типа помещается в разделе
объявления типов, начинающегося с ключевого слова type, и имеет синтаксис, как показано в следующем примере с двумерным массивом (название типа, знак равенства и структура типа, оканчивающаяся точкой с запятой). Пользовательский тип данных удобно использовать при объявлении
переменных или параметров подпрограмм, когда один и тот же тип востребован в разных частях программы. Название типа выбирают таким,
чтобы было понятно, для хранения каких данных он предназначен.
Пример объявления двумерного массива вещественных чисел
и обнуления значений всех его элементов
const
M = 5;
N = 4;
type
TMatrix1 = array[1..N] of Real;
TMatrix2 = array[1..M, 1..N] of Real;
var
M: TMatrix2;
I, J: Integer;
begin
for I := 1 to M do
for J := 1 to N do
M[I, J] := 0;
При объявлении многомерных массивов можно использовать расши-
ренный вариант синтаксиса, как показано в следующем примере.
TMatrix2 = array[1..M] of array[1..N] of Real;
TMatrix2 = array[1..M] of TMatrix1;
Немного забегая вперед, скажем, что в Delphi встроена поддержка
так называемых динамических массивов, т. е. массивов, размер которых
можно изменять в процессе выполнения программы. При объявлении динамического массива не указывается диапазон индексов, его размер задается вызовом процедуры SetLength, принимающей в качестве параметров
переменную-массив и размер массива, который следует установить. Элементы динамических массивов нумеруются с 0. Текущий размер массива
29

Глава 1
можно узнать, вызвав функцию Length. Динамические массивы, как и статические, могут быть многомерными.
При работе с массивами используются такие наиболее распростра-
ненные операции, как:
нахождение суммы элементов массива;
нахождение минимального (максимального) элемента в массиве;
изменение структуры массива (перестановка строк и столбцов
массива);
упорядочение элементов массива (сортировка массива);
другие.
Первые из приведенных операций просты и в пояснениях не нуждаются.
Алгоритмы сортировки
В основной массе современного программного обеспечения исполь-
зуются алгоритмы сортировки (или упорядочения) данных. Что касается
сортировки, то причина ее использования достаточно понятна – в упорядоченном наборе данных можно быстрее производить поиск, при этом не
требуется выполнять полный перебор.
Существующие алгоритмы сортировки можно объединить в четыре
группы: сортировки выбором, сортировки методом включения, обмена
и слияния. В каждой группе можно выделить алгоритм-родоначальник
общего подхода упорядочения, на основании которого были получены
другие методы. Ниже приводится список некоторых алгоритмов с кратким
пояснением на примере упорядочения одномерного массива из N целых
чисел. Для алгоритма указывается вычислительная сложность – оценка зависимости требуемого в общем виде количества операций сравнения от
количества элементов N как O(N) («O» большое от N).
Сортировка выбором: набор чисел условно разделяется на два на-
бора, уже упорядоченный и еще нет; изначально упорядоченный набор
пуст. В неупорядоченном наборе выбирается минимальный элемент и помещается последним в уже упорядоченный набор; эти действия выполняются до тех пор, пока неупорядоченный набор не будет исчерпан. Вычислительная сложность: O(N
2
).
Сортировка включением (вставками): последовательно, начиная со
второго, перебираются все элементы массива, каждый I-й элемент помещается на подходящее место в упорядоченном наборе из предыдущих элементов (с 1-го по I-й включительно). Вычислительная сложность: O(N
2
).
Сортировка обменом (пузырьковая): последовательно сравнива-
ются рядом стоящие пары элементов массива и при необходимости обмениваются. Выполняется столько проходов массива, пока не прекратятся
обмены, в худшем случае N – 1 проход. Вычислительная сложность: O(N
2
).
30
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
