Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Turbo Pascal / Stud_1_1 / LecRus / MainPart.doc
Скачиваний:
117
Добавлен:
03.03.2016
Размер:
5.03 Mб
Скачать

Обработка в процедуре матриц с различными именами типов

Обработка матриц различного размера (с разными именами типов) организуется в процедуре с помощью аппарата приведения типов или с помощью абсолютных переменных в основном аналогично тому, как это выполняется для одномерных массивов. Разница в их обработке связана с тем, что внутреннее представление одномерного массива и матрицы неодинаково.

Элементы одномерного массива расположены в памяти последовательно.

Пример 1.

Type RealAr = array[1..1000] of real;

Xar = array[1..500] of real;

Var X : Xar;

Y : RealAr;

c,d : real;

Begin ................

c:=X[100];

d:=RealAr(X)[100];

При старте программы выделяется память для переменных X, Y, c и d, соответственно 3000, 6000, 6 и 6 байтов. Поле X имеет следующую структуру:

X+0 X+6 X+12 X+18 . . . X+2988 X+2994

. . .

На этой схеме снизу указаны элементы массива X, сверху - их адреса. Каждый элемент занимает 6 байтов памяти. В частности, элемент имеет адрес X+(100-1)  6 = X+594.

Поле Y имеет аналогичную структуру, последний элемент расположен по адресу Y+5994.

Запись RealAr(X) означает, что в данном случае поле X интерпретируется как переменная, имеющая тип RealAr. Поскольку описание RealAr определяет одномерный массив с элементами типа real, то элемент RealAr(X)[100] имеет тот же адрес, что и элемент . Следовательно, переменные c и d в приведенном выше примере получают одинаковые значения.

Элементы матрицы расположены в памяти по строкам.

Пример 2.

Type Rem = array[1..100,1..100] of real;

MatrixA = array[1..20,1..30] of real;

Var A : MatrixA; B : Rem;

c,d : real;

Begin ...............

c:=A[10,10];

d:=Rem(A)[10,10];

Переменные A и Rem(A) - это одно и то же поле памяти. Элементы матрицы A расположены в памяти согласно трафарета, определенного именем типа MatrixA, т.е.

a[1,1], a[1,2], ... , a[1,29], a[1,30],

a[2,1], a[2,2], ... , a[2,29], a[2,30],

..................................................

a[20,1], a[20,2], ... , a[20,29], a[20,30]

Следовательно, элемент имеет порядковый номер 9  30 + 10 = 280, его адрес равен A + (280-1)6 = A + 1674.

Расположение в памяти элементов матрицы Rem(A) определено именем типа Rem:

Rem(A)[1,1], Rem(A)[1,2], ..., Rem(A)[1,99], Rem(A)[1,100],

Rem(A)[2,1], Rem(A)[2,2], ..., Rem(A)[2,99], Rem(A)[2,100],

..............................................................

Rem(A)[100,1],Rem(A)[100,2],...,Rem(A)[100,99],Rem(A)[100,100]

Элемент Rem(A)[10,10] имеет порядковый номер 9  100 + 10 = 910, его адрес равен

A + (910-1)*6 = A + 5454.

Следовательно, переменным c и d в примере 2 будут присвоены различные значения.

Совпадение значений a[i,j] и Rem(A)[i,j] будет иметь место лишь в том случае, когда пределы изменения индексов фактической и наложенной матриц одни и те же. Естественно, при этих условиях процедура не сможет правильно обрабатывать матрицы разного размера.

Чтобы обеспечить в процедуре обработку матриц разного размера, в теле процедуры на фактическую матрицу накладывается фиктивный одномерный массив. Тогда при переходе от фактического к фиктивному (наложенному) массиву по индексам i, j матрицы вычисляется порядковый номер k одномерного массива, а при обратном переходе - по значению k вычисляются индексы i, j.

Пусть фактическая матрица A имеет объявление типа

Matrix = array[1..Mmax,1..Nmax] of real.

Тогда порядковый номер элемента a[i,j]: k = (i - 1)  Nmax + j .

Наоборот, элемент с порядковым номером k имеет индексы

i = (k - 1) div Nmax + 1; j = k - (i - 1)  Nmax.

Пример 3. Разработать процедуру, определяющую значение и местоположение максимального элемента для матриц разного размера.

Program MaxElem;

Const MmaxA = 30; NmaxA = 30;

MmaxB = 20; NmaxB = 40;

Type MatrixA = array[1..MmaxA,1..NmaxA] of real;

MatrixB = array[1..MmaxB,1..NmaxB] of real;

RealAr = array[1..(2*MaxInt) div SizeOf(real)] of real;

Var i,j, { параметры цикла }

ma,na,mb,nb, { размеры матриц A и B}

imaxA,jmaxA, { индексы макс.элемента }

imaxB,jmaxB : byte; { для матриц A и B }

Amax,Bmax : real; { значение макс.элемента }

A : MatrixA; B : MatrixB;

FileA,FileB : text;

{ ----------------------------------------------- }

Procedure ReadMatrix(Var F:text; Var C; Nmax:byte; Var m,n:byte);

{ Чтение матрицы из файла }

Var i,j : byte;

k : word;

R : real;

Begin

Reset(F);

Read(F,m,n);

For i:=1 to m do

For j:=1 to n do

Begin

Read(FileX,R);

k:=(i-1)*Nmax+j; RealAr(C)[k]:=R;

End;

Close(F);

End { ReadMatrix };

{ ----------------------------------------------- }

Procedure MaxMatrix(Var C; Nmax,m,n:byte; Var Cmax:real;

Var imax,jmax:byte);

{ Определение значения и местоположения макс.эл-та матрицы }

Var i,j : byte;

k : word;

Begin

Cmax:=RealAr(C)[1]; imax:=1; jmax:=1;

For i:=1 to m do

For j:=1 to n do

Begin

k:=(i-1)*Nmax+j;

If RealAr(C)[k]>Cmax then

Begin

Cmax:=RealAr(C)[k]; imax:=i; jmax:=j;

End;

End;

End { MaxMatrix };

{ ----------------------------------------------- }

Begin

Assign(FileA,'MatrixA.dat');

ReadMatrix(FileA,A,NmaxA,ma,na):

MaxMatrix(A,NmaxA,ma,na,Amax,imaxA,jmaxA);

Writeln('Amax= ',Amax:8:2,' imaxA= ',imaxA,

' jmaxA= ',jmaxA);

Assign(FileB,'MatrixB.dat');

ReadMatrix(FileB,B,NmaxB,mb,nb);

MaxMatrix(B,NmaxB,mb,nb,Bmax,imaxB,jmaxB);

Writeln('Bmax= ',Bmax:8:2,' imaxB= ',imaxB,

' jmaxB= ',jmaxB);

End.

В примере 3 для обработки матриц с разными именами типов применялся аппарат приведения типов. В следующем примере с этой же целью используются абсолютные переменные.

Пример 4. Разработать процедуру, определяющую значение и местоположение максимального элемента среди элементов, расположенных ниже главной диагонали квадратной матрицы.

Program MaxMatrix;

Const NmaxA = 30; NmaxB = 40;

Type MatrixA = array[1..NmaxA,1..NmaxA] of real;

MatrixB = array[1..NmaxB,1..NmaxB] of real;

RealAr = array[1..(2*MaxInt) div SizeOf(real)] of real;

Var i,j, { параметры цикла }

na,nb, { размеры матриц A и B }

imaxA, { индексы макс.элемента }

jmaxA, { для матрицы А }

imaxB, { индексы макс.элемента }

jmaxB : byte; { для матрицы B }

Amax,Bmax : real; { значение макс.элемента }

A : MatrixA; B : MatrixB;

FileA,FileB : text;

{ ----------------------------------------------- }

Procedure ReadMatrix(Var F:text; Var C; Nmax:byte;

Var n:byte);

{ Чтение матрицы из файла }

Var i,j : byte;

k : word;

R : real;

D : RealAr absolute C;

Begin

Reset(F); Read(F,n);

For i:=1 to n do

For j:=1 to n do

Begin

Read(F,R);

k:=(i-1)*Nmax+j; d[k]:=R;

End;

Close(F);

End { ReadMatrix };

{ ----------------------------------------------- }

Procedure MaxElem(Var C; Nmax, n:byte; Var max:real;

Var imax,jmax:byte);

{ Определение значения и местоположения максимального }

{ элемента матрицы ниже главной диагонали }

Var i,j : byte;

D : RealAr absolute C;

Begin

max:=d[Nmax+1]; imax:=2; jmax:=1; { первый элемент }

For i:=3 to n do { второй строки }

For j:=1 to i-1 do

Begin

k:=(i-1)*Nmax+j;

If d[k]>max then

Begin

max:=d[k]; imax:=i; jmax:=j;

End;

End;

End { MaxElem };

{ ----------------------------------------------- }

Begin

Assign(FileA,'MatrixA.dat');

ReadMatrix(FileA,A,NmaxA,na):

MaxMatrix(A,NmaxA,na,Amax,imaxA,jmaxA);

Writeln('Amax= ',Amax:8:2,' imaxA= ',imaxA,

' jmaxA= ',jmaxA);

Assign(FileB, 'MatrixB.dat');

ReadMatrix(FileB,B,NmaxB,nb):

MaxMatrix(B,NmaxB,nb,Bmax,imaxB,jmaxB);

Writeln('Bmax= ',Bmax:8:2,' imaxB= ',imaxB,

' jmaxB= ',jmaxB);

End.

О П Е Р А Т О Р В А Р И А Н Т А (О П Е Р А Т О Р В Ы Б О Р А)

Условный оператор выбирает одну из двух альтернатив. Если альтернатив более двух, удобно использовать оператор варианта (оператор Case).

Примечание. Слово «case» по-английски означает «случай».

Синтаксис оператора Case:

Выражение, входящее в состав оператора варианта, называют селектором. Оператор варианта состоит из селектора и списка операторов, с каждым из которых сопоставляется одна или несколько констант, относящихся к типу селектора. Тип селектора должен быть ординальным.

Оператор варианта выбирает для выполнения оператор, сопоставленный с текущим значением селектора. Если такая константа не обнаружена, выполняется ветвь Else, при отсутствии которой оператор варианта эквивалентен пустому оператору.

В списке констант допускается использование диапазонов.

Пример 1.

Var k : 1..10;

Begin

..........

Case k of

1 : y:=x+1;

2 : y:=sin(x);

3..5 : y:=sqrt(x);

6 : y:=exp(x);

7 : y:=sqr(x);

end;

Следует особо отметить, что в операторе варианта перед двоеточием стоит не метка, а константа ординального типа.

Пример 2.

Var ch : char;

Begin

Case ch of

'a' : Writeln('Первая ветвь');

'b','c','d' : Writeln('Вторая ветвь');

'p'..'t' : Writeln('Третья ветвь')

Else

Writeln('Альтернативная ветвь');

end;

Примечание. В соответствии с синтаксической диаграммой перед словом else в операторе Case, в отличие от условного оператора, может стоять точка с запятой. Следовательно, в предыдущем примере оператор Case можно записать в виде

Case ch of

'a' : Writeln('Первая ветвь');

'b','c','d' : Writeln('Вторая ветвь');

'p'..'t' : Writeln('Третья ветвь');

Else

Writeln('Альтернативная ветвь');

end;

М А С С И В Ы С И М В О Л О В

Строки, состоящие из одного символа, считаются константами типа char. Например, 'a', 'A', '1', '=' .

Строки, состоящие из n символов, считаются константами типа

array[1..n] of char.

По отношению к символьным массивам действуют в основном те же правила, что и по отношению к числовым массивам. В частности, присваивание A := B допустимо лишь в том случае, когда типы массивов A и B тождественны.

Пример 1.

Type Ar1 = array[1..10] of char;

Ar2 = array[1..10] of char;

Ar3 = Ar1;

Var A : Ar1; B : Ar2; C : Ar3;

Begin

......................

B:=A; C:=A;

Здесь оператор C:=A будет считаться корректным, а для оператора B:=A компилятор выдаст сообщение «Type mismatch», поскольку типы Ar1 и Ar2 не являются тождественными.

Тем не менее имеются и отличия в обработке символьных и числовых массивов.

В частности, символьному массиву можно присвоить значение строки символов, если количество символов в строке и объявленный размер символьного массива одинаковы. Например, для предыдущего примера правильным будет воспринят оператор A:=’0123456789’, а для операторов B:=’01234567’ и C:=’0123456789012’ будет выдано сообщение «Type mismatch».

Для символьных массивов допустимы также операции отношения. Такие операции выполняются слева направо до тех пор, пока не встретятся два неодинаковых символа. Если длины массивов различные, то более короткий дополняется символом #0.

Пример 2.

Var p : boolean;

A,B,C : array[1..8] of char;

Begin

A:='ABCDEFGH'; B:='ABCDXYZV'; C:=B;

p:=A<C;

В данном случае получим p = true.

Пример 3. Слова в тексте разделены одним или несколькими пробелами. Определить, сколько слов оканчиваются буквой 'а'.

Program Letter;

Const Nmax = 60;

Var i,k,n : integer;

Tex : array[1..Nmax] of char;

Begin

Read(n);

For i:=1 to n do { Ввод текста }

Read(Tex[i]); { по одному символу }

For i:=1 to n do { Вывод текста }

Write(Tex[i]); { по одному символу }

Writeln;

k:=0;

For i:=1 to n-1 do { если после буквы }

If (Tex[i]='a') and { следует пробел, то }

(Tex[i+1]=' ') then { это означает, что }

Inc(k); { данная буква является }

If Tex[n]='a' then { последней в слове }

Inc(k);

Writeln('k= ',k);

End.

Поскольку текст - это массив символов, то ввод и вывод такого текста осуществляется поэлементно, по одному символу.

Пример 4. Даны два слова одинаковой длины. Определить, состоят ли эти слова из одних и тех же букв. Например, 'СОСНА' = 'НАСОС', но 'СОСНА'  'НАНОС', так как в слове 'СОСНА' две буквы 'С', а в слове 'НАНОС' - только одна такая буква.

Обозначим заданные слова именами Slovo1 и Slovo2. Будем выбирать по одной букве из Slovo2 и последовательно сравнивать выбранную букву со всеми буквами в Slovo1. Если i-ая буква в Slovo2 равна j-ой букве в Slovo1, то j-ую букву первого слова заменяем на пробел (чтобы эта буква больше не анализировалась при наличии в Slovo2 повторяющихся букв). Если равенство Slovo1[j] = Slovo2[i] не обнаружено, дальнейшая проверка должна быть прекращена.

Обычно в программах не рекомендуется искажать исходные данные (в данном случае в процессе работы программы стираются буквы в Slovo1). Поэтому сравнение Slovo2 будет производиться с буферным (рабочим) словом SlovoBuf, в которое на стартовом участке программы копируется значение Slovo1.

Program Slovo;

Const n = 20;

Var i,j : byte;

Cond : boolean;

Slovo1,Slovo2,SlovoBuf : array[1..n] of char;

Begin

Ввод и печать Slovo1,Slovo2

SlovoBuf:=Slovo1;

For i:=1 to n do

Begin

Cond:=false;

For j:=1 to n do

If Slovo2[i]=SlovoBuf[j] then

Begin

SlovoBuf[j]:=' '; Cond:=true;

Break;

End;

If not Cond then

Break;

End;

If Cond then

Writeln('Слова имеют одинаковые буквы')

Else

Writeln('Слова имеют различные буквы');

End.

Здесь следует обратить внимание на то, что каждый оператор Break осуществляет выход лишь за пределы того цикла, в котором он сам находится.

С Т Р О К И

Обработка текста в виде массива символов сопряжена с рядом недостатков.

1. Символьный массив обрабатывается в цикле по одному элементу, вследствие чего программа становится громоздкой.

2. Cимвольному массиву можно присвоить значение строки символов лишь в том случае, когда длина строки и объявленный размер массива одинаковы.

Чтобы исключить указанные недостатки, в Турбо Паскале введен тип данных string. Переменная типа string в отличие от массива символов может принимать значения переменной длины. При объявлении такой переменной указывается ее максимальная длина.

Объявление строки имеет вид:

Соседние файлы в папке LecRus