Type
Kmang1 = array[1.2] of array[1.3] of Real;
Kmang2 = array[‘a’.’c’] of array[1.3] of String[15];
Var
X : Kmang1;
Y : Kmang2;
Hiểu theo cách này thì X là một mảng gồm hai phần tử X[1] và X[2] mà
mỗi phần tử này lại là một mảng gồm 3 phần tử :
X[1] là mảng có 3 phần tử kiểu thực X[1][1], X[1][2], X[1][3]
X[2] là mảng có 3 phần tử kiểu thực X[2][1], X[2][2], X[2][3]
Ðiều tương tự cũng áp dụng cho biến mảng Y.
Hai cách viết X[i][j] và X[i,j] cùng chỉ một phần tử.
22 trang |
Chia sẻ: maiphuongdc | Lượt xem: 26151 | Lượt tải: 2
Bạn đang xem trước 20 trang tài liệu Pascal - Mảng hai chiều (ma trận), để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
MẢNG HAI CHIỀU (MA TRẬN)
10.2.1. Khai báo mảng hai chiều:
Mảng hai chiều, còn gọi là ma trận, là sự mở rộng trực tiếp của mảng một
chiều. Ta cũng có hai cách khai báo.
Cách 1: Khai báo trực tiếp :
VAR
Tênmảng : Array[n1..n2 , m1..m2] of Tênkiểudữliệu;
trong đó n1, n2 là các hằng có cùng kiểu dữ liệu và n1 n2, chúng xác định
phạm vi của chỉ số thứ nhất, gọi là chỉ số dòng. Tương tự m1, m2 là các
hằng có cùng kiểu dữ liệu và m1 m2, chúng xác định phạm vi của chỉ số
thứ hai, gọi là chỉ số cột. Giống như mảng một chiều, kiểu dữ liệu của các
chỉ số chỉ có thể là kiểu đếm được: nguyên, ký tự, lô gic, liệt kê hay đoạn
con, không được là kiểu thực hay chuỗi.
Ví dụ, cho khai báo :
Var
X : array[1..2, 1..3] of Real;
Y : array[‘a’..’c’ , 1..3] of String[15];
Kết quả ta nhận được hai mảng hai chiều:
Mảng X gồm 6 phần tử cùng kiểu dữ liệu thực:
X[1,1], X[1,2], X[1,3]
X[2,1], X[2,2], X[2,3]
Mảng Y gồm 9 phần tử cùng kiểu chuỗi String[15] :
Y[‘a’,1], Y[‘a’,2], Y[‘a’, 3]
Y[‘b’,1], Y[‘b’,2], Y[‘b’, 3]
Y[‘c’,1], Y[‘c’,2], Y[‘c’, 3]
Có thể ví X là một nhà hai tầng, mỗi tầng có ba phòng giống nhau. Các
tầng được đánh số từ 1 đến 2, trong mỗi tầng, các phòng được đánh số từ 1
đến 3. Tương tự, Y là một nhà ba tầng, các tầng được đánh số lần lượt là ‘a’,
‘b’, ‘c’, mỗi tầng có ba phòng được đánh số lần lượt là 1, 2, 3.
Cách 2: Biến mảng được khai báo thông qua một kiểu mảng đã được
định nghĩa trước đó bằ?g từ khóa TYPE, tức là:
TYPE
Tênkiểumảng= Array[n1..n2 , m1..m2] of Tênkiểudliệu;
VAR
Tênmảng : Tênkiểumảng ;
Ví dụ: Hai mảng X và Y nói trên có thể được khai báo theo hai bước sau:
Type
Kmang1 = array[1..2, 1..3] of Real;
Kmang2 = array[‘a’..’c’ , 1..3] of String[15];
Var
X : Kmang1;
Y : Kmang2;
Chú ý: - Có thể xem mảng hai chiề? là mảng một chiều mà mỗi phần tử
của nó lại là một mảng một chiều.
Hai mảng X, Y nói trên có thể khai báo như sau:
Type
Kmang1 = array[1..2] of array[1..3] of Real;
Kmang2 = array[‘a’..’c’] of array[1..3] of String[15];
Var
X : Kmang1;
Y : Kmang2;
Hiểu theo cách này thì X là một mảng gồm hai phần tử X[1] và X[2] mà
mỗi phần tử này lại là một mảng gồm 3 phần tử :
X[1] là mảng có 3 phần tử kiểu thực X[1][1], X[1][2], X[1][3]
X[2] là mảng có 3 phần tử kiểu thực X[2][1], X[2][2], X[2][3]
Ðiều tương tự cũng áp dụng cho biến mảng Y.
Hai cách viết X[i][j] và X[i,j] cùng chỉ một phần tử.
Khai báo và gán giá trị ban đầu:
Có thể khai báo và gán giá trị ngay cho một mảng hai chiều, chẳng hạn:
Type
Kmang1 = array[1..2, 1..3] of Real;
Const
X : Kmang1 = ( (1.5, 2.5, 3.5), (5.0, 6.5, 7.0) );
Khi đó X là một mảng hai chiều có 6 phần tử cùng kiểu thực và có giá trị
là:
X[1,1]=1.5, X[1,2]=2.5, X[1,3]=3.5
X[2,1]=5.0, X[2,2]=6.5, X[2,3]=7.0
Cần nhấn mạnh rằng mặc dù từ khóa ở đây là Const song X và các phần
tử của X có thể dùng như các biến, tức là các phần tử của X có thể thay đổi
giá trị được.
10.2.2. Các thao tác trên ma trận :
Ðể xác định một phần tử trong mảng hai chiề?, ta viết:
Tênbiếnmảng[chỉ số 1, chỉ số 2]
Ví dụ:
X[1,1]:=12.5;
X[2,1]:=X[1,1]+15;
Y[‘a’,1]:=‘Tran Thi Mai’;
Ðể nhập dữ liệu cho một mảng hai chiều, ta phải dùng hai vòng lặp duyệt
theo hai chỉ số, chẳng hạn muốn nhập dữ liệu cho mảng X, ta viết:
For i:=1 to 2 do
For j:=1 to 3 do
begin
Write(‘nhập phần tử hàng ‘, i, ‘ cột ‘, j , ‘: ‘);
Readln(X[i, j]);
end;
Tương tự, lệnh nhập dữ liệu cho mảng Y được viết là:
For ch:=‘a’ to ‘c’ do
For j:=1 to 3 do
begin
Write(‘nhập phần tử hàng ‘, ch , ‘ cột ‘, j , ‘: ‘);
Readln(X[ch, j]);
end;
trong đó ch là biến kiểu ký tự, còn i và j là các biến nguyên.
Ðể in mảng X lên màn hình, trình bày giống như cách viết ma trận, mỗi
hàng in trên một dòng, ta dùng lệnh :
For i:=1 to 2 do
begin
For j:=1 to 3 do write(X[i, j]:3:1); { in hàng thứ i}
Writeln; { xuống dòng, chuẩn bị in hàng tiếp theo }
end;
10.2.3. Các ví dụ về ma trận :
Vì ma trận là mảng một chiều của các mảng một chiều nên nhiều bài toán
về mảng được mở rộng tự nhiên cho ma trận.
Ví dụ 10.6: Tính tổng của hai ma trận
Nhập vào hai ma trận A, B cấp NxM. Tính ma trận C là tổng của hai ma
trận A và B, in ma trận C lên màn hình.
Công thức tính các phần tử của ma trận C= A+B :
C[i,j ] = A[i, j] + B[i, j] với i=1,..., N, và j=1,..., M
Chương trình như sau:
PROGRAM VIDU106;
{ Tính tổng hai ma trận }
Uses CRT;
Var
A, B, C : Array[1..10, 1..10] of Real;
i, j , N, M : Integer;
Begin
Clrscr;
Repeat
Write(‘Nhập số hàng N, số cột M : ‘);
Readln(N, M);
Until ( N>0) and ( N0) and (M<11);
For i:=1 to N do
For j:=1 to M do
begin
Write(‘Nhập A[‘ , i, ‘,’ , j , ‘]: ‘);
Readln(A[i,j]);
end;
{ nhập B và tính C luôn}
For i:=1 to N do
For j:=1 to M do
begin
Write(‘Nhập B[‘ , i, ‘,’ , j , ‘]: ‘);
Readln(B[i,j]);
C[i, j]:=A[i, j] + B[i, j];
end;
{ In ma trân A lên màn hình }
Writeln(‘ Ma tran A la :’);
For i:=1 to N do
begin
For j:=1 to M do write(A[i, j]:3:0);
Writeln;
end;
{ In ma trân B lên màn hình }
Writeln(‘ Ma tran B la :’);
For i:=1 to N do
begin
For j:=1 to M do write(B[i, j]:3:0);
Writeln;
end;
{ In ma trân C lên màn hình }
Writeln(‘ Ma tran C la :’);
For i:=1 to N do
begin
For j:=1 to M do write(C[i, j]:3:0);
Writeln;
end;
Readln;
End.
Chạy chương trình
Chép tập tin nguồn
Ví dụ 10.7: Tìm số lớn nhất (số nhỏ nhất) trong ma trận A:
Giả sử A là ma trận N hàng, M cột, và Max là biến chứa số lớn nhất phải
tìm. Khởi đầ? ta gán A[1,1] cho Max, sau đó duyệt tất cả các phần tử của ma
trận, nếu phần tử nào lớn hơn Max thì lưu nó vào Max, tức là:
Max:=A[1,1];
For i:=1 to N do
For j:=1 to M do
if Max< A[i, j] then Max:=A[i, j];
Writeln(‘ Số lớn nhất là ’, Max);
Ví dụ 10.8 : Tìm số lớn nhất (hay số nhỏ nhất) trong từng hàng (hay
từng cột) của ma trận A:
Hàng i ( 1 i N ) của ma trận A có dạng :
A[i,1], A[i,2], ..., A[i,M]
Nếu xem i là cố định thì đó là mảng một chiều có M phần tử, nên số lớn
nhất của hàng i được tìm bằng các lệnh:
Max:=A[i, 1];
For j:=1 to M do
if Max< A[i, j] then Max:=A[i, j];
Writeln(‘Sln của hàng ‘, i, ‘ là: ‘, Max) ;
Vì có cả thảy N hàng nên công việc trên phải làm N lần ứng với i=1, 2, ...,
N, tức là:
For i:=1 to N do
begin { tìm số lớn nhất của hàng i }
Max:=A[i, 1];
For j:=1 to M do
if Max< A[i, j] then Max:=A[i, j];
Writeln(‘Sln của hàng ‘, i, ‘ là: ‘, Max) ;
end;
Ví dụ 10.9: Kiểm tra ma trận vuông A có đối xứng không ?.
Ma trận vuông A gọi là đối xứng nếu nó không thay đổi khi ta đổi cột
thành hàng và đổi hàng thành cột. Nói cách khác, ma trận A là đối xứng khi
và chỉ khi A[i,j] =A[j,i] với mọi i=1, ..., N và với mọi j=1, .., N. Ví dụ, cho
hai ma trận dưới đâỵ:
thì A là đối xứng, còn B không đối xứng vì B[1,2] B[2,1].
Chỉ cần có một cặp i, j sao cho A[i,j]A[j,i] thì A là ma trận không đối
xứng.
Vậy các lệnh kiểm tra tính đối xứng của ma trận A là:
Kiemtra := TRUE;
For i:=1 to N do
For j:=1 to N do
if A[i, j]A[j, i] then Kiemtra:=FALSE ;
If Kiemtra=TRUE then writeln(‘ Ðối xứng ‘)
else
writeln(‘ Không đối xứng ‘);
Trong đó Kiemtra là một biến kiểu lôgic.
Nhận xét rằ?g hai lệnh For ở trên quét qua tất cả các phần tử của ma trận
nên có hơn nửa số lần lặp là thừa. Thật vậy, đường chéo chính chia ma trận
ra làm hai phần: nửa trái và nửa phải. Các phầ? tử trên đường chéo chính thì
đối xứng với chính nó nên không cần phải kiểm tra. Nếu mỗi phầ? tử ở nửa
bên trái đều bằng phần tử đối xứng với nó ở nửa bên phải thì ma trận rõ ràng
là đối xứng. Vì vậy chỉ cần duyệt kiểm tra các phần tử ở nửa bên trái đường
chéo chính là đủ (vùng tam giác).
Thuật toán tốt hơn được đề nghị là :
Kiemtra := TRUE;
For i:=2 to N do
For j:=1 to i-1 do
if A[i, j]A[j, i] then Kiemtra:=FALSE ;
If Kiemtra=TRUE then writeln(‘ Ðối xứng ‘)
else
writeln(‘ Không đối xứng ‘);
Hai câu lệnh For trên vẫn còn một nhược điểm là: khi xảy ra A[i,j]A[j,
i] rồi, lẽ ra có thể dừng lại và kết luận không đối xứng ngay thì các vòng For
vẫn tiếp tục, i chạy đến N và j đến i-1.
Sử dụng câu lệnh While sẽ khắc phục được nhược điểm này. Chỉ cần xảy
ra A[i,j]A[j,i] một lần là biến Kiemtra được gán ngay gía trị FALSE, khi
đó điều kiện Kiemtra=TRUE bị sai và cả hai vòng lặp đều kết thúc .
Kiemtra:=TRUE;
i:=2;
While (Kiemtra=TRUE) and (i<= N) do
begin
j:=1;
While ( Kiemtra=TRUE) and ( j<=i-1) do
if A[i, j] A[j, i] then Kiemtra:=FALSE
else
j:=j+1;
i:=i+1;
end;
If Kiemtra=TRUE then writeln(‘ Ðối xứng ‘)
else
writeln(‘ Không đối xứng ‘);
Chương trình dưới đây thực hiện các công việc sau:
Nhập vào ma trận vuông A cấp N và in ma trận A lên màn hình
Ðếm trong ma trận A có bao nhiêu số 0
Tìm số lớn nhất trong A
Tìm số nhỏ nhất trong từng hàng của A
Kiểm tra xem A có phải là ma trận đối xứng không.
PROGRAM VIDU109;
Uses CRT;
Type
Matran = Array[1..10, 1..10] of Real;
Var
A : Matran;
i, j , N, Dem : Integer;
Max, Min : Real;
Kiemtra: Boolean;
Begin
Clrscr;
Repeat
Write(‘Nhập cấp N : ‘);
Readln(N);
Until ( N>0) and ( N<11) ;
For i:=1 to N do
For j:=1 to N do
begin
Write(‘Nhập A[‘, i, ‘,’ , j , ‘]: ‘);
Readln(A[i,j]);
end;
{ In ma trân A lên màn hình }
Writeln(‘ Ma tran A la : ’);
For i:=1 to N do
begin
For j:=1 to N do write(A[i, j]: 3 :0);
Writeln;
end;
{ Ðếm số số 0 }
Dem:=0;
For i:=1 to N do
For j:=1 to N do if A[i, j]=0 then Inc(Dem);
Writeln(‘ Có ‘, Dem, ‘ số không’);
{ Tìm số lớn nhất của ma trận }
Max:=A[1,1];
For i:=1 to N do
For j:=1 to N do
if Max < A[i,j] then Max:=A[i,j];
Writeln(‘ Số lớn nhất của ma trận= ‘, Max : 4:1);
{ Tìm số nhỏ nhất trong từng hàng của ma trận }
For i:=1 to N do
begin
Min:=A[i,1];
For j:=1 to N do if Min > A[i,j] then Min:=A[i,j];
Writeln(‘ Số nhỏ nhất của hàng ‘, i , ‘ là: ‘, Min : 4:1);
end;
{ Kiểm tra ma trận có đối xứng không}
Kiemtra:=True;
For i:=1 to N do
For j:=1 to i-1 do
if A[i ,j]A[j ,i] then Kiemtra:=False;
If Kiemtra=True then Writeln(‘ Ðối xứng’)
else
Writeln(‘ Không đối xứng’) ;
Readln;
End.
Chạy
Chép tập tin nguồn