Интервальные типы данных. Оператор TYPE. Массивы
Интервальные типы данных. Оператор TYPE. Массивы
С.А. Григорьев
Интервальный тип - это некоторый подтип порядкового
типа данных (вспомним, что порядковые типы - это ShortInt, Byte, Integer, Word,
LongInt, Char и Boolean). Пусть, например, некоторая переменная в программе
может принимать значения от -1 до 99. Мы могли бы описать ее как LongInt или
Integer (глупо!), могли бы описать ее как ShortInt, что достаточно разумно. Но
можно создать для нее и специальный тип данных, объединяющий только числа от -1
до 99 :
VAR x :
-1..99;
Вместо имени одного из стандартных типов мы
использовали в описании переменной построенный нами собственный интервальный
тип. Таким образом описанная переменная x может принимать только значения
-1,0,1,...,99 , в остальном она ничем не отличается от других целых переменных.
Ее можно вводить, выводить, использовать в качестве переменной цикла,
подставлять в выражения и т.п. Любой интервальный тип есть подтип некоторого
стандартного базового типа, в нашем случае - типа ShortInt. Но если бы мы стали
использовать интервальный тип -1..200 , то он бы уже был подтипом типа Integer,
а 0..200 - подтипом типа Byte. Компилятор Паскаля самостоятельно анализирует
интервальные типы и подбирает для них минимальный подходящий базовый тип. Это
нужно знать, чтобы определять размер и способ кодировки ваших переменных. Вы
можете выполнить оператор
WRITE('переменная x:-1..99 занимает
',SizeOf(x),' байт');
и убедиться, что ее размер действительно равен 1.
В качестве базового типа можно использовать не только
арифметические типы, но и типы Char и Boolean (правда, в последнем случае это
довольно бессмысленно). Опишем, например, переменную, значением которой могут
быть только маленькие латинские буквы :
VAR Letter : 'a'..'z';
или переменную, в которой могут храниться русские
буквы:
VAR
RusLetter : 'А'..'я';
В общем случае интервальный тип описывается как
константное
выражение 1 .. константное выражение 2,
где оба выражения имеют один порядковый тип и второе
из них не меньше первого. Созданным вами типам вы можете давать имена, для
этого используется оператор TYPE :
TYPE имя типа=описание типа;
Операторы TYPE так же, как и все другие операторы
описания, записываются в разделе описаний. В программе может быть сколько
угодно операторов TYPE, и их можно чередовать с другими операторами описания,
но любые идентификаторы, использованные в описании типа, должны быть описаны
раньше. После того, как некоторый тип получил имя, вы в дальнейшем можете
пользоваться этим именем вместо полного описания типа :
CONST Tmin=-5;
Tmax=15;
TYPE T_Range_Type=Tmin..Tmax;
VAR
t:T_Range_Type;
TYPE T_Range_SubType=Tmin+3..Tmax-5;
VAR
t1:T_Range_SubType;
Заметим, что хороший программист всегда дает имена
собственным типам, причем старается, чтобы эти имена были осмысленными.
Теперь, зная об интервальных типах, мы можем говорить
о массивах. Массив во всех языках программирования - это множество
индексированных (пронумерованных) однотипных элементов. В Паскале описание
одномерного массива имеет вид:
ARRAY [тип индекса] OF тип элемента
Здесь тип индекса - ShortInt, Byte, Char, Boolean или
интервальный тип; тип элемента - любой тип, в том числе и массив. Вы заметили,
что не все порядковые типы можно использовать как тип индекса, это не значит,
что, например, тип Word чем-то хуже типа Byte. Такое ограничение обусловлено
тем, что в Паскале никакой объект не может иметь размер больше (64К - 2) байта,
или 65534 байта. Это ограничение действует и для интервальных типов, так вы
можете описать массив VAR a : ARRAY[1..65534] OF BYTE;
но не массив VAR a :
ARRAY[1..65535] OF BYTE;
и не массив VAR a : ARRAY[1..33000] OF WORD;
Больше никаких ограничений на тип индекса не
накладывается. Тип элементов массива может быть любым - целочисленным,
вещественным, символьным, логическим, интервальным. Элементы массива могут быть
массивами, тогда вы получите массив размерностью больше чем 1. Опишем несколько
массивов:
VAR a : ARRAY[Char] OF 1..5;
- массив из 256 элементов, каждый из которых есть
целое число от 1 до 5, индексы элементов изменяются от #0 до #255;
CONST Max = 99;
Min = 10;
TYPE Nums =
Min..Max;
TYPE ArrayType =
ARRAY[-10..0] OF Nums;
VAR a :
ArrayType;
- массив из 11 элементов с индексами от -10 до 0,
каждый элемент - целое положительное число из двух цифр;
TYPE IndexType =
'a'..'z';
VAR a :
ARRAY[IndexType] OF BOOLEAN;
- массив из 26 элементов с индексами от 'a' до 'z',
каждый элемент - логическая переменная.
В программе вы можете использовать как массивы
целиком, так и отдельные элементы массивов. Элемент одномерного массива
записывается в виде:
имя
массива [ индексное выражение ]
Индексное выражение - это любое выражение
соответствующего типа. Если элемент массива - не массив, то с ним можно
выполнять любые операции, разрешенные для простых переменных соответствующего
типа. Целому массиву можно лишь присваивать массив того же типа. Заметим, что
если массивы описаны в программе таким образом:
VAR a :
ARRAY[1..3] OF REAL;
b,c,d : ARRAY[1..3] OF REAL;
TYPE Massiv=ARRAY[1..3] OF REAL;
VAR e,f : Massiv;
g
: Massiv;
h,i
: Massiv;
то массивы b,c,d - однотипные и массивы e,f,g,h,i тоже
однотипные, но массивы a и b (a и c,a и d) имеют разный тип; и массивы b
(c,d,a) и e (f,g,h,i) тоже имеют разный тип! Компилятор считает, что две
переменные имеют один и тот же тип, только если они описаны в одном операторе
через запятую, либо имена их типов одинаковы! Запомните это очень важное
правило.
Запишем пример программы, использующей (пока
одномерные) массивы:
{ программа вводит массив из N целых чисел, где N не
превосходит 20, и выводит его в порядке неубывания }
CONST Nmax=20;
TYPE IndexType=1..Nmax;
Massiv=ARRAY[IndexType] OF Integer;
VAR a : Massiv; i,j,N : IndexType; t :
Integer;
BEGIN
WRITELN;
REPEAT
WRITE('Введите длину массива от 1 до ',Nmax,' ');
READ(N);
WRITELN;
UNTIL (N>=1)AND(N<=Nmax);
{
Вводим массив поэлементно }
WRITELN('Введите
элементы массива');
FOR i:=1 TO N DO
READ(a[i]);
{
Сортируем элементы массива по неубыванию. Используем очень простой, но
неэффективный алгоритм сортировки - сравниваем
каждый элемент с каждым
и, если первый больше второго, меняем их местами }
FOR i:=1 TO N-1 DO FOR j:=i+1 TO N DO
IF a[i]>a[j] THEN BEGIN t:=a[i];
a[i]:=a[j]; a[j]:=t; END;
{
Выводим отсортированный массив поэлементно }
WRITELN('Результат сортировки :');
FOR i:=1 TO N DO WRITE(a[i]:8);
END.
Обратите внимание на алгоритм перестановки двух
элементов! Запись a[i]:=a[j]; a[j]:=a[i]; , очевидно, привела бы к неверному
результату. Использованный нами алгоритм сортировки вполне надежен, но не очень
хорош, так как выполняет много лишних операций. Не составляет труда
усовершенствовать его - для каждого i от 1 до N-1 найдем наименьший из
элементов ai, ai+1, ... , aN и поместим его на i-е место; такой алгоритм
выполняет столько же сравнений, сколько и первоначальный, но требует
существенно меньшего количества перестановок.
FOR i:=1 TO N-1 DO BEGIN
a_max:=a[i]; n_max:=i;
FOR j:=i+1 TO N DO
IF a[j]<a_max THEN BEGIN
a_max:=a[j]; n_max:=j; END;
IF n_max<>i THEN BEGIN
a[n_max]:=a[i]; a[i]:=a_max; END;
END;
Как видите, запись алгоритма несколько длиннее, и
потребовалось две новых переменных a_max - типа Integer и n_max - типа
IndexType. Это действие универсального закона сохранения - из двух верных
алгоритмов лучший, как правило, сложнее.
Теперь перейдем к рассмотрению многомерных массивов.
Размерностью, или количеством измерений массива, называется количество индексов
у элемента массива, но не количество элементов в массиве. Мы уже знаем, что
элемент массива может быть массивом, поэтому двумерный массив можно описать,
например, так :
VAR a :
ARRAY[1..10] OF ARRAY[1..20] OF Real;
Переменную a можно рассматривать как одномерный массив
одномерных массивов и использовать в программе запись вида a[i] ; но можно
рассматривать и как двумерный массив вещественных чисел. Элемент этого массива
записывается в программе в виде a[ индексное выражение , индексное выражение ]
и является переменной типа Real, например, a[i+1,3]. Впрочем, можно записать и
так: a[i+1][3], обе эти записи эквивалентны. Описание многомерных массивов
также можно записывать компактно: вместо
ARRAY[ t1 ] OF ARRAY[ t2 ] OF ARRAY ... OF t ;
можно записать
ARRAY[ t1 , t2 , ... ] OF t ;
Впрочем, бывают случаи, когда первое описание
предпочтительней. Теперь, умея работать с многомерными массивами, напишем
программу, перемножающую две квадратные вещественные матрицы:
CONST Nmax=20; {максимальный размер матрицы}
TYPE IndexType=1..Nmax;
Matrix
=ARRAY[IndexType,IndexType] OF Real;
VAR
a,b,c : Matrix; n,i,j,k : IndexType;
BEGIN
WRITE('введите размер матриц '); READ(n);
IF (n<1)OR(n>Nmax) THEN BEGIN
WRITELN('неверный размер!'); Halt; END;
WRITELN('введите
матрицу A построчно ');
FOR i:=1 TO n DO
FOR j:=1 TO n DO READ(a[i,j]);
WRITELN('введите
матрицу B построчно ');
FOR i:=1 TO n DO
FOR j:=1 TO n DO READ(b[i,j]);
FOR i:=1 TO n DO FOR j:=1 TO n DO
BEGIN
c[i,j]:=0; FOR k:=1 TO n DO
c[i,j]:=c[i,j]+a[i,k]*b[k,j]; END;
WRITELN('матрица A*B :');
FOR i:=1 TO n DO FOR j:=1 TO n DO WRITE(c[i,j]);
WRITELN;
END.
Наша программа сработала правильно, но полученную
матрицу вывела плохо - все элементы подряд без деления на строки. Исправим алгоритм вывода:
FOR i:=1 TO n DO BEGIN
FOR j:=1 TO n DO WRITE(c[i,j]:8);
WRITELN;
END;
Теперь матрица выводится аккуратно.
В Паскале допускаются типизированные константы -
массивы, список значений элементов массива задается в круглых скобках и
разделяется запятыми:
CONST a : ARRAY[1..5] OF Byte=(1,2,3,4,5);
c : ARRAY[0..3] OF
Char=('a','b','c','d');
b : ARRAY[-1..1] OF
Boolean=(FALSE,TRUE,FALSE);
Символьные массивы можно инициализировать и более
простым способом:
CONST c : ARRAY[0..3] OF Char='abcd';
Если инициализируется многомерный массив, то,
поскольку каждый его элемент есть массив, нужно использовать вложенную
скобочную структуру:
CONST A : ARRAY[1..3,1..2] OF Real =
((0,1),(2,4),(3,5));
Каким именно образом сгруппировать значения элементов,
легко понять, вспомнив, что массив ARRAY[1..3,1..2] OF Real есть на самом деле
компактная запись описания ARRAY[1..3] OF ARRAY[1..2] OF Real.
Итак, мы узнали, что кроме величин известных нам
арифметических, символьного, логического типа и интервальных типов, каждая из
которых имеет одно значение, существуют массивы - совокупности многих значений.
Первые величины называются скалярными, а массивы и ряд других типов, пока нам
не известных, структурированными величинами.
Список литературы
Для подготовки данной работы были использованы
материалы с сайта http://elib.albertina.ru/