Иванова Г.С. - Основы программирования
.pdf4. Структурные типы данных
Например:
^) 2_-6_8_56_34 J - символ «J» означает нажатие клавиши Enter;
6)2 J -6 J 8 J 56 J 34 J
При выполнении операций ввода-вывода матриц и массивов большой размерности целесообразно вводить и выводить значения построчно.
Например:
Var a:arrayfl..5, LJ] |
of real; |
{матрица a из 5 строк по 7 элементов} |
Begin |
|
|
for /;=7 to 5 do |
{цикл ввода строк массива: aj, а2, аз, а4, аз) |
|
begin |
|
|
forj:-l to 7 do |
|
{цикл ввода элементов i-й строки:} |
Read(a[iyj]); |
{aj j, aj 2, a,-3, aj 4, aj 5, a^ 5, aj 7} |
|
ReadLn; {очищаем буфер ввода}
end;...
Пример 4.L Разработать программу определения максимального эле мента массива А(5) и его номера.
Вначале элементы массива необходимо ввести. Для выполнения этой операции используем цикл с заданным числом повторений.
Поиск максимального элемента выполним следующим образом. Запом ним в качестве максимального, т. е. запишем в атах первый элемент и зафик сируем в imax его номер. Затем будем последовательно просматривать эле менты массива, сравнивая их со значением, хранящимся в атах. Если оче редной элемент больше значения в атах, то сохраняем его в качестве макси мального в атах и запоминаем его номер в imax (рис. 4.4). Для организации последовательного просмотра используем цикл с заданным числом повторе ний, изменяя переменную цикла от 2 до 5, так как первый элемент мы уже учли. Просмотрев все элементы массива, найдем максимальный элемент и его номер. После этого необходимо вывести на экран исходный массив, мак симальный элемент и его номер.
На рис. 4.5 представлена схема алгоритма программы. Поскольку опе рации ввода-вывода массивов выполняют однотипно, на схеме алгоритма со ответствующих циклов, так же как и запросов на ввод данных, обычно не по казывают. Вместо этого в схему вставляют блок операции ввода/вывода, в
81
Часть 1. Основы алгоритмизации и процедурное программирование
атах |
1 |
2 |
3 |
4 |
5 |
amax |
1 |
2 |
3 |
4 |
5 |
| 3 . 5 | |
1 3.5 |
-5.1 |
0 |
8.4 |
-0.3 |
8.4 |
3.5 |
-5.1 |
0 |
8.4 |
-0.3 |
imax |
|
i |
|
|
|
max |
|
i |
|
|
|
1— — ! |
|
|
|
|
|
|
|
|
|
||
|
L "*J |
|
|
UU |
|
LiJ |
|
|
|||
ш |
|
|
|
|
|
|
|||||
|
|
a |
|
|
|
|
|
б |
|
|
|
Рис. 4.4, Поиск максимального элемента массива:
а- состояние на момент проверки четвертого элемента массива; б - изменение текущего значения максимального элемента и его номера по результатам проверки четвертого элемента массива
котором указано имя массива и количество элементов, участвующих в операции. Ниже приведен текст программы.
Рис. 4.5. Схема алгоритма поиска максимального элемента массива
Program ex;
Var a:array[l.,5] of real; amax:real;
/, imax:byte; Begin
{запрос на ввод массива}
WriteLn(*Введите 5 чисел: *);
{ввод элементов массива} for /.-=7 to 5 do Read(a[i]); ReadLn;
{поиск максимального элемента} amax:=aflj;
imax:-J;
for i:=2 to 5 do ifa[i]>amax then
begin amax:=a[ij; imax.'^i;
end;
{вывод массива}
WriteLnCИсходные данные: *); for /.•=; to 5 do Write(a[i]:5:2); WriteLn;
{вывод результата}
WriteLnCМаксимальный элемент равен \ атах:5:2, \ его номер равен \ imax);
End
82
4. Структурные типы данных
1 |
3.1 |
5.7 |
8.1 |
-0.7 |
3.6 |
1 |
19.8 |
2 |
4.3 |
6.8 |
-0.3 |
5.7 |
9.2 |
2 |
25.7 1 |
3 |
6.4 |
2.7 |
5.5 |
-5.3 |
2.7 |
3 |
12.0 |
4 |
5.1 |
-2.7 |
7.7 |
1.7 |
5.1 |
4 |
16.9 |
|
|
|
а |
|
|
|
б |
Рис. 4.6. Исходные данные (а) и результат (б) примера 4.2
Пример 4.2. Разработать программу вычисления сумм элементов строк матрицы А(4,5). Полученные суммы записать в новый массив В.
Итак, нам задана матрица, имеющая 4 строки и 5 столбцов (рис. 4.6, а). Требуется сформировать одномерный массив В из четырех элементов, кото рый будет содержать суммы элементов строк (рис. 4.6, б). Распечатать ре зультат лучше так, чтобы суммы были выведены после соответствующей
строки матрицы, как на рис. 4.6. |
|
|
|
|
|
|
Программа должна начинаться со ввода мат |
Г Начало |
J |
|
|||
рицы. Основной цикл программы - цикл по стро |
|
|
|
|
|
|
кам. Переменная цикла i в нем будет изменяться от |
/ |
Ввод |
|
7 |
|
|
1 до 4. Дпя каждой i-й строки в этом цикле долж |
/ |
А(4,5) |
|
/ |
|
|
но выполняться суммирование элементов. Сумми |
|
|
|
|
|
|
рование будем осуществлять методом накопления, |
|
=1,4,1 |
|
|
|
|
для чего перед суммированием обнулим соответ |
|
|
|
|
||
|
|
|
|
|
||
ствующий i-й элемент массива В, а затем в цикле |
j |
1 |
|
j |
|
|
выполним добавление элементов строки. После |
\ |
B[i]:=0 |
|
|
|
|
завершения цикла суммирования эту строку и ее |
|
|
|
|
|
|
сумму можно сразу выводить. На рис. 4.7 пред |
r * ^ j : = I , 5 , l \ - , |
|
||||
ставлена схема алгоритма программы (пунктиром |
|
|||||
выделено суммирование элементов i-й строки). |
1 B[i]:=B[i]+ |
|
1 |
j |
||
Ниже приведен ее текст. |
|
|
||||
Program ex; |
|
11 |
-^t'ji |
|
1 |
h |
|
1 |
1 |
|
|
; |
|
Var А: array[L .4J„5J |
ofreal; |
|
Вывод |
|
/ |
|
B:array[1..4] ofreal; |
/ |
_m_J |
|
|
||
ij:byte; |
|
|
|
|
|
|
Begin |
|
{ |
Конец |
j |
|
|
WriteLn(*Введите Mampuify построчно: *); |
|
|||||
|
|
|
|
|
||
for i:=J to 4 do |
{вводим матрицу} |
|
|
|
|
|
begin |
|
Рис. 4.7. Схема |
|
|||
forj:^l to 5 do Read(A[iJ]); |
алгоритма программы |
|||||
ReadLn; |
|
нахождения сумм |
|
|||
end; |
|
элементов строк |
|
|||
83
Часть L Основы алгоритмизации и процедурное программирование
WriteLn(*Результаты:');
for i:=^l to 4 do {для каждой строки}
begin |
|
|
B[i]:=0; |
{обнуляем накапливаемую сумму} |
|
forj:-l |
to 5 do BfiJs^BfiJ-^AfiJJ; {суммируем элементы строки} |
|
forj:=I |
to 5 do Write(A[ij]:7:2); |
(выводим строку} |
WriteLnC Сумма равна \B[i]:7:2); |
{выводим сумму} |
|
end; |
|
|
End
Символьные массивы. Символьными называют массивы, элементами которых являются символы. Такие массивы традиционно использовались для представления символьной информации, например различных текстов. Обработка символьных массивов в Borland Pascal имеет некоторые особен ности.
1. Объявляя символьный массив как типизированную константу, значе ния символов можно указывать поэлементно:
Const d:array[l,JO] of char ^С0\ Ч\ '2\ '3\ *4\ '5\ '6'/7\ |
'8\ V*); |
или целиком, используя строковую константу, длина которой должна строго соответствовать размеру массива:
Const d:array[L.10] of char = VI23456789';...
2. Присвоить значение символьному массиву также можно целиком, ис пользуя строковую константу, длина которой должна совпадать с длиной массива:
Var S: array[LJl] of char;...
S:- 'Примеродин*;
3. При вводе элементы символьного массива нельзя разделять пробела ми, так как пробел будет восприниматься как символ:
Var S: array[1„ 10] of char;...
for i:=l to 10 do Read(S[i]); {вводим строку «ABODE FILN J»}
4. Символьный массив можно выводить поэлементно в цикле, как обыч ный одномерный массив, а можно - целиком, одним рператором Write или WriteLn:
WriteLn(S); {вывод символьного массива одним оператором}
5. В операторе вывода допускается использование операции конкатена ции (слияния) символьных массивов, обозначаемой символом «+». Результа том этой операции будет новый символьный массив, число элементов кото-
84
4. Структурные типы данных
рого равно сумме размеров исходных массивов, а значениями элементов - элементы исходных массивов, последовательно записанные друг за другом:
WriteLn(stl + ' * + st2): {конкатенация символьных массивов}
Работа с одномерными символьными массивами осуществляется поэле ментно, как с обычными массивами. Рассмотрим пример использования сим вольных массивов.
Пример 4.3. Дана строка не более 40 символов, состоящая из слов; раз деленных пробелами, и завершающаяся точкой. Разработать программу уда ления «лишних» пробелов. Лишними считать пробелы в начале строки, вто рой и более пробелы между словами и пробелы в конце строки.
Например:
Исходная строка: ABC DE FGH Результат: ABC_DE__FGH.""
Удалить пробелы в начале строки не трудно: просто не нужно переписы вать пробелы до первого значащего символа из исходной строки в результи рующую. Несколько сложнее дело обстоит с пробелами между словами, так как удалить нужно не все пробелы, а только повторяющиеся. Для решения задачи используем специальный признак «первый пробел». Этот признак бу дем устанавливать, встретив первый пробел, и гасить, встретив символ, от личный от пробела (на рис. 4.8). Используя этот признак, мы сможем отли чить первый пробел, который необходимо перенести в массив результата от последующих, которые переносить не надо. Диаграмма показывает, что если в конце строки есть пробелы, то с использованием признака «первый про бел» мы получим в строке результата один лишний пробел. Поэтому после завершения обработки необходимо проверить признак, и если он установлен, удалить пробел, уменьшив длину строки на единицу. В программе, приведен ной ниже, вместо этого на место пробела пишется точка. В том случае, если пробела в конце нет, для точки «добавляется» элемент.
|
|
Исходный массив |
|
Признак |
А В С |
D Е ^ |
F G Н |
true |
|
|
|
"первый |
XZZZL |
|
|
пробел" |
false |
|
|
|
А В С |
D Е |
F G Н |
|
|
Результат |
|
Рис. 4.8. Диафамма установки и гашения признака «первый пробел»
85
Часть 1. Основы алгоритмизации и процедурное программирование
Program Stroka; |
|
|
|
|
|
|
Var ij\n:byte; |
key:boolean; |
|
|
|||
s:array [L.41] of char; |
{дополнительный символ - для точки} |
|
||||
Begin |
|
|
|
|
|
|
WriteLnCВведите исходную строку длиной до 40 символов: |
*); |
|||||
i:-l; |
{вводим строку посимвольно до точки, но не более 40 символов} |
|||||
Read(s[i]); |
|
|
|
|
|
|
while (i<40) and (s[i]o\') |
do |
|
||||
begin |
|
|
|
|
|
|
i:-i+l; |
|
|
|
|
|
|
Read(sfiJ); |
|
|
|
|
||
end; |
|
|
|
|
|
|
ReadLn; |
|
|
|
|
|
|
ifsfij= |
\ ' then n:=i'l |
else n:=i; {определяем количество введенных |
|
|||
|
|
|
|
|
символов без точки} |
|
Writef'BeedeHHaM строка: *); WriteLn(s); |
|
|||||
j:=0; |
{номер символа в строке результата} |
|
||||
key:=false; |
{гасим признак "первый пробел"} |
|
||||
for i:=J to п do |
|
|
|
|
||
ifs[i]^* * then |
{если обнаружен пробел} |
|
||||
begin |
|
|
|
|
|
|
|
if key then |
{этот пробел первый} |
|
|||
|
begin |
|
|
|
|
|
|
|
key:=false; {дальше пойдут лишние пробелы} |
|
|||
|
|
j:=j+J: |
{пробел переписываем в результат} |
|
||
|
|
s[j]:^s[i]; |
|
|
||
|
end; |
|
|
|
|
|
end |
|
|
|
|
|
|
else |
{символ} |
|
|
|
|
|
begin |
|
|
|
|
|
|
|
key:=true; |
|
{устанавливаем признак "первый пробел"} |
|
||
|
s/jj:=sfi]; |
{символ переписываем в результат} |
|
|||
end; |
|
|
|
|
|
|
if key thenj:=j+l; |
|
{если пробела в конце нет, то увеличиваем |
|
|||
|
|
|
|
|
длину для записи точки} |
|
S[/]:'= \ V {записываем точку}
WriteLn('npeo6pa3oeaHHaM строка '); for i:=J toj do Write(s[i]); WriteLn;
End.
86
4.Структурные типы данных
4.2.Практикум. Обработка одномерных массивов
Все операции, которые приходится выполнять над элементами одномер ных массивов, можно разбить на следующие классы:
•последовательная обработка элементов массивов;
•переформирование массивов;
•одновременная обработка нескольких массивов или подмассивов;
•поиск элементов массива по заданным критериям.
Как правило, в реальной жизни задачи, включающие только эти опера ции, встречаются редко. Однако программирование более сложной обработ ки включает элементы указанных операций.
Для выполнения перечисленных выше операций разработаны соответст вующие приемь}. Рассмотрим наиболее распространенные приемы програм мирования обработки одномерных массивов.
Последовательная обработка элементов массивов. Особенностью операций данного класса является то, что количество обрабатываемых эле ментов массива и шаг изменения индексов известны. Это позволяет для вы полнения операции использовать счетный цикл, через переменную которого обеспечивается косвенный доступ к элементам. Если просматриваются все элементы массива, то обращение выполняют, используя переменную цикла в качестве индекса, а если с заданным шагом, то для адресации элементов строится выражение, в которое входит переменная цикла, например 2*i+l. Однако возможно применение и других типов циклов.
Примерами задач, требующих выполнения последовательной обработ ки, являются: ввод и вывод массивов, нахождение сумм элементов как цели ком массива, так и его определенной части, произведения элементов, средне го арифметического, среднего геометрического, подсчет количества элемен тов, отвечающих определенному условию или обладающих некоторыми при знаками, а также их суммы, произведения и т.д. Кроме того, к этой группе могут быть отнесены задачи формирования значений и замены значений всех элементов значениями, подчиняющимися определенному закону.
Пример 4,4. Разработать программу определения среднего арифметиче ского значений положительных элементов целочисленного массива А(п), где п < 40, кратных трем.
Количество элементов массива в условии не определено, но ограничено. Для реального массива, который будет обрабатываться программой, это ко личество естественно должно быть известно. Следовательно, прежде чем вводить элементы массива, можно запросить у пользователя ввод количества элементов п. Массив при этом будем описывать на максимально возможное количество элементов, так как в Borland Pascal выделение памяти под масси вы реализовано статически^ т. е. память под массивы, строки и другие струк турные типы данных резервируется на этапе компиляции программы. Если
87
Часть 1, Основы алгоритмюации и процедурное программирование
s:=s+A[i]
kol:=kol+l
I
Конец
Рис. 4.9. Алгоритм определения среднего арифметического элементов массива, кратных 3
необходимо реализовать выделение па мяти во время выполнения программы, то используют указатели (см. главу 7).
Для решения самой задачи необхо димо двум вспомогательным перемен ным S и ко1, которые будут использова ны для накопления суммы требуемых элементов и их количества, присвоить нулевые значения. После этого осуще ствляют перебор всех элементов, и если очередной удовлетворяет условию, его значение добавляют к содержимому пе ременной S, а значение переменной ко1 увеличивают на единицу. После про смотра всего массива среднее арифме тическое может быть определено деле нием накопленной суммы на количест во найденных элементов. (Обратите внимание, что среднее арифметическое определяется после просмотра всего
массива, так как до этого момента у нас не полные сумма и количество элемен тов.) Положительных элементов в мас сиве может не быть, что необходимо предусмотреть в программе. Алгоритм решения задачи представлен на рис. 4.9. Ниже представлен текст программы.
Program ex;
Var a:array[L JO] of integer; s, kol /, n:integer; Begin
WriteLn(*Введите количество элементов массива <=40*);
Readlnfn); {вводим количество элементов массива} |
|
WriteLn(*Введите \ п, * элементов массива: |
*); |
for i:=l to п do Read(a[i]); |
|
ReadLn; {вводим массив} |
|
WriteLnf* Исходный массив *); |
|
for i:'=J to n do {выводим массив по 10 элементов в строке} if О mod 10) =0 then WriteLn(a[i]:5)
else Write(a[i]:5); WriteLn;
kol:-0; {обнуляем количество элементов, кратных 3} s:-0\ {обнуляем начальное значение суммы элементов}
88
4, Структурные типы данных
for i:=l to п do
if(a[i] mod 3)=0 then {если элемент кратен 3} begin
kol:=kol+l\ {увеличиваем количество на 1} s:-s-¥a[i]; {добавляем элемент к сумме}
end;
ifkol='0 then {если количество элементов равно нулю, то}
}¥гиеЬпСЭлементов, удовлетворяющих условию, нет*) else WriteLnC Среднее арифметическое^ ко1:3,
^ элементов, кратных 3-*,(s/kol):7:2);
End
Пример 4.5. Для целочисленного массива А(п), где п<10, разработать программу, определяющую количество отрицательных элементов среди эле ментов, стоящих в массиве на местах с четными номерами. Элементы масси ва пронумерованы, начиная с единицы.
Для решения задачи необходимо проверить все элементы массива, име ющие значение индекса 2, 4, 6 и т.д. Поскольку количество повторений цик ла несложно определить: оно равно п div 2, используем счетный цикл, выра зив индекс элемента через переменную цикла: 2*i.
Для подсчета количества искомых элементов вводим вспомогательную переменную kol, начальное значение которой равно 0. Если проверяемый элемент отрицателен, то значение переменной kol увеличивается на единицу. После обхода всего массива переменная kol будет содержать искомое значе ние.
Program ex;
Var a:array[L. 10] of integer; kol Lj, n:integer; Begin
WriteLnCBeedume количество элементов массива <=10*);
ReadLn(n); {вводим количество элементов}
WriteLnCBeedume \п, * элементов массива *);
for |
i:=l |
to п do ReadfafiJ); {вводим массив} |
|
WriteLnCВведенный массив'); |
|
||
for |
i:=l |
to n do Write(a[i]:3); WriteLn; {выводим исходный массив} |
|
kol:-0; |
{обнуляем количество отрицательных элементов} |
||
for |
i:-l |
to п div 2 do |
|
|
ifa[2*i]<0 then |
{если элемент отрицателен, то} |
|
|
|
kol:=kol+l; |
{увеличиваем количество на 1} |
ifkol-=0 then
WriteLnCОтрицательных элементов на четных местах нет*) else
WriteLnCKoлuчecmвo отрицательных элементов ко1-\ ко1:3);
End
89
Часть L Основы алгорипщизации и процедурное программирован
Переформирование массива. Переформирование массива предполага ет изменение порядка элементов посредством их перемещения, удаления или вставки. При переформировании массива его размер может изменяться, а мо жет оставаться без изменений.
Следует учесть, что вставка или удаление элементов осуществляется за счет сдвига всех элементов той части массива, которая расположена после удаляемого или вставляемого элемента. В зависимости от конкретных усло вий иногда такой сдвиг может быть совмещен с последовательной обработ кой оставшихся элементов. В остальных случаях он должен выполняться в специальном вложенном цикле.
Пример 4.6. Дан массив А(п), где п < 10, и число В. Разработать про грамму удаления из массива всех элементов, меньших заданного значения В.
Для получения требуемого результата необходимо последовательно пе ребрать все элементы массива. Если очередной элемент меньше В, то его сле дует удалить, сдвигая на один элемент все элементы, расположенные после него. Если в массиве были найдены элементы меньше В, то полученный мас сив будет иметь меньший размер.
Для решения этой задачи можно предложить два алгоритма: с отдельной и встроенной реализацией сдвига элементов.
П е р в ы й а л г о р и т м представляет собой решение задачи «в лоб»: нашли элемент - исключили его, сдвинув остальные элементы, нашли следу ющий - исключили его и т. д. (рис. 4.10).
В т о р о й а л г о р и т м базируется на том, что нам не требуется, что бы в момент анализа элементов массива все элементы располагались подряд без пропусков. Следовательно, можно, используя две переменные для кос венной адресации, отслеживать как исследуемые элементы исходного масси ва, так и уже полученные элементы результирующего массива. Например, пусть переменная i изменяется в цикле и обеспечивает адресацию следую щего анализируемого элемента. Тогда переменную к увеличиваем на едини-
1 |
Сдвинуть |
1 |
|
I 2 \ | |
I 2\1 |
:ш |
|
0.5 |
-2.1 9.8 |
[ 3.5 1 0.5[Ж 9.8 |
|
Размер массива=5 |
Размер массива=4 |
|
|
в |
|
В |
|
Ш2 |
|
СЮ |
|
Рис. 4.10. Этапы выполнения программы:
а - обнаружен элемент меньше заданного; б - остальные элементы сдвигаем на его место, уменьшаем размер массива и вновь анализируем элемент с тем же номером i
90
