Khởi đầu, Max được gán giá trị A[1]. Sang bước 2, Max được so sánh với
A[2] để chọn ra số lớn nhất giữa A[1], A[2] và lưu vào biến Max. Sang bước
3, Max được tiếp tục so sánh với A[3] để tìm ra số lớn nhất giữa A[1], A[2],
A[3], .v.v. Kết qủa, sau bước n, biến Max sẽ chứa số lớn nhất của dãy A[1],
A[2], ., A[n].
29 trang |
Chia sẻ: maiphuongdc | Lượt xem: 16513 | Lượt tải: 5
Bạn đang xem trước 20 trang tài liệu Pascal - Mảng một chiều, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
MẢNG MỘT CHIỀU
10.1.1. Mảng và cách khai báo mảng :
Khái niệm :
Mảng là một tập gồm nhiều phần tử có cùng chung một kiểu dữ liệu. Mỗi
phần tử của mảng có một đại lượng xác định vị trí tương đối của phần tử đó
so với các phần tử khác trong mảng, gọi là chỉ so? Các yếu tố để xác định
một mảng gồm có:
Tên mảng
Kiểu dữ liệu chung của các phần tử trong mảng
Kiểu dữ liệu của chỉ số và phạm vi của chỉ số.
Kiểu dữ liệu của các phần tử mảng là mọi kiểu dữ liệu mà một biến có thể
có. Tuy nhiên, kiểu dữ liệu của chỉ số thì không được là kiểu thực hay kiểu
chuỗi, nó chỉ có thể là kiểu đếm được : nguyên, ký tự, lôgic, liệt kê hay đoạn
con.
Khai báo mảng một chiều :
Mảng một chiều, còn gọi là dãy, hay đơn giản là mảng, có thể khai báo
theo một trong hai cách :
Cách 1: Khai báo trực tiếp theo cách sau :
VAR
Tênmảng : Array[m1 . . m2] of Tênkiểudữliệu ;
Ở đây m1, m2 là hai hằ?g xác định phạm vi của chỉ số, chúng có chung
một kiểu dữ liệu,?và m1 m2.
Ví dụ: Cho khai báo dưới đây:
Var
A : Array[0..10] of Real;
Hten: Array[1..5] of String[18];
B: Array[‘a’..’d’] of Integer;
Theo khai báo trên, ta có ba mảng:
Mảng thứ nhất tên là A, gồm 11 phần tử cùng kiểu Real, ứng với
các chỉ số 0, 1, 2, ..., 10, đó là:
A[0], A[1], A[2], ..., A[10]
Mảng thứ hai tên là HTen gồm 5 phần tử cùng kiểu dữ liệu là
String[18] ứng với các chỉ số từ 1 đến 5:
Hten[1], Hten[2], Hten[3], Hten[4], Hten[5]
Mảng thứ ba tên là B, gồm 4 phần tử cùng kiểu Integer ứng với các chỉ
số ‘a’, ‘b’, ‘c’, ‘d’:
B[‘a’], B[‘b’], B[‘c’], B[‘d’]
Ðể có một hình ảnh về mảng, đối với mảng A, ta hình dung có một dãy
nhà một tầng, tên gọi là dãy A, gồm 11 phòng liên tiếp giống hệt nhau được
đánh số thứ tự từ 0,1, 2, ..., đến 10 :
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10
Tương tự, mảng B cũng giống như dãy nhà B một tầng có 4 phòng được
đánh số thứ tự là các chữ a, b, c, d :
Ba Bb Bc Bd
Cách 2 : Khai báo qua một kiểu dữ liệu mới, gồm hai bước:
Bước 1: Ðịnh nghĩa kiểu dữ liệu mảng :
TYPE
Tênkiểumảng = Array[m1 . . m2] of Tênkiểudữliệu;
Bước 2: Khai báo biến có kiểu dữ liệu là kiểu mảng:
VAR
Tênmảng : Tênkiểumảng ;
Ví dụ, đối với các mảng A, B và Hten ở trên ta có thể khai báo theo cách
2, như sau:
Type
Mang1 = array[0..10] of Real;
Mang2 = array[1..5] of String[18];
Mang3 = array[‘a’..’d’] of Integer;
Var
A : Mang1;
Hten: Mang2;
B: Mang3;
Khai báo mảng có gán trị ban đầu:
Pascal cho phép vừa khai báo mảng vừa gán gía trị ban đầu cho các phần
tử mảng, chẳng hạn như dưới đây:
Const
X : array[1..5] of Integer = (12, 14, 16, 18, 20) ;
Khi đó X là một mảng gồm 5 phần tử cùng kiểu nguyên và có giá trị
X[1]=12, X[2]=14, X[3]=16, X?4]=18, X[5]=20.
Mặc dù từ khóa ở đây là Const song X lại được dùng như là một biến
mảng, tức là các phần tử của X có thể thay đổi gía trị được. Ví dụ, trong
chương trình ta có thể gán:
X[1]:= 2;
X[2]:=5+20;
10.1.2. Truy xuất các phần tử mảng:
Các xử lý trên mảng được quy về xử lý từng phần tử mảng. Ðể xác định
một phần tử của mảng, ta dùng cách viết :
Tênmảng[ chỉ số của phầ? tử ]
Ví du : có thể gán :
A[0]:= 15.8;
A[1]:= 2*A[0];
Hten[3]:= ‘Nguyen Thi Loan’;
B[‘a’]:=100;
Chỉ số của một phần tử có thể là một biến, một hằng, hay một biểu thức.
Ví dụ, cho i là biến kiểu nguyên, khi đó ta có thể dùng các lệnh:
i:=6;
A[i]:=100.25;
Hai lệnh trên tương đương với một lệnh:
A[6]:=100.25;
Nếu biến i có giá trị là 6 thì lệnh :
A[ i div 2 +1] := 4.5; tương đương với lệnh:
A[4]:=4.5; vì biểu thức i div 2 +1 có gía trị là 4.
Khi nhập dữ liệu cho các phần tử của một mảng , ta có thể dùng câu lệnh
For, While hay Repeat.
Ví dụ, nhập dữ liệu cho các phần tử của mảng A:
For i:=0 to 10 do
begin
Write(‘Nhập phần tử thứ ‘ , i , ‘: ‘);
Readln(A[i]);
end;
hoặc (dùng While) :
i:=0;
While i<= 10 do
begin
Write(‘Nhap phần tử thứ ‘, i, ‘: ‘);
Readln(A[i]);
i:=i+1;
end;
Tương tự để nhập dữ liệu cho các phần tử của mảng B, ta viết:
For ch:=‘a’ to ‘d’ do
begin
Write(‘Nhap phần tử thứ ‘, ch, ‘: ‘);
Readln(B[ch]);
end;
Ðể in các gía trị của mảng A lên màn hình, ta viết :
For i:=0 to 10 do Write(A[i]:6:2);
Các gía trị của mảng A sẽ được in liên tiếp nhau trên cùng một dòng. Còn
nếu muốn in mỗi phần tử trên một dòng, ta thay lệnh Write bằ?g Writeln.
Tương tự, mảng B được in lên màn hình bằng lệnh :
For ch:=‘a’ to ‘d’ do Write(B[ch]);
Chú ý : Turbo Pascal cho phép gán một mảng này cho một mảng khác.
Nếu X, Y là hai biến mảng cùng một kiểu mảng thì lệnh:
X := Y;
có nghĩa là lấy gía trị của từng phần tử của mảng Y gán cho phần tử tương
ứng trong mảng X. Ví dụ, cho khai báo:
Var
X, Y : Array[1..10] of Real;
Khi đó, lệnh: X := Y;
tương đương với lệnh :
For i:=1 to 10 do X[i] :=Y[i];
10.1.3. Các bài toán cơ bản về mảng :
Ví dụ 10.1: Ðếm số lần xuất hiện của gía trị x trong dãy A1, A2, ..., An .
Ví dụ gía trị x=6 xuất hiện 3 lần trong dãy 6 7 1 2 6 0 6 1.
Ta dùng biến Dem kiểu nguyên để đếm số lần xuất hiện của x. Ðầu tiên ta
gán Dem:=0, sau đó duyệt từng phần tử A1, A2, ..., An, mỗi khi có một phần
tử bằng x thì tăng biến Dem lên một đơn vị. Kết qủa là biến Dem có gía trị
đúng bằng số phần tử bằng x. Hai lệnh chính của thuật toán là:
Dem:=0;
For i:=1 to N do If A[i]=x then Dem:=Dem+1;
Ví dụ, đếm trong dãy số A có bao nhiêu số 0, ta viết:
Dem:=0;
For i:=1 to N do if A[i]=0 then Dem:=Dem+1;
Writeln(‘ Có ‘, Dem , ‘ số không ‘);
Nhận xét: Ðẳng thức A[i]=x ( hay A[i]=0 ) là điều kiện để biến Dem
được tăng thêm 1, vậy bài toán trên có thể mở rộng là: hãy đếm số phần tử
của mảng A thỏa mãn một điều kiện cho trước. Trong lệnh For ở trên, khi
thay đẳng thức A[i]=x bằng A[i] thỏa điều kiện , ta được thuật toán tổng
quát hơn :
Dem:=0;
For i:=1 to N do If A[i] thỏa điều kiện then Dem:=Dem+1;
Chương trình sau nhập một mảng A có N phần tử, in mảng A lên màn
hình, và đếm xem mảng A có bao nhiêu số dương :
PROGRAM VIDU101;
{ Ðếm số dương trong mảng}
Type
Kmang = Array[1..20] of Real;
Var
A: Kmang;
i, N, Dem : Integer;
Begin
Repeat
Write(‘ Nhập số phần tử N : ‘);
Readln(N);
Until (N>0) and ( N<21);
{ nhập mảng }
For i:=1 to N do
begin
Write(‘Nhập A[‘ , i , ‘ ]: ‘);
Readln( A[i] );
end;
{ In mảng A}
Writeln(‘ Mảng A là : ’);
For i:=1 to N do Write(A[i]:3:0);
Writeln;
{ đếm số dương }
Dem:=0;
For i:=1 to N do If A[i]>0 then Dem:=Dem+1;
Writeln(‘ Số số dương = ‘ , Dem );
Readln;
End.
Chạy
Chép tập tin nguồn
Ví dụ 10.2: Tìm số lớn nhất của dãy A1, A2, ..., An.
Trong bài 8, ta đã chỉ ra cách tìm số lớn nhất của hai số, của ba số. Có thể
mở rộng thuật toán đó để tìm số lớn nhất của n số :
Gọi Max là biến chứa số lớn nhất phải tìm, thế thì :
Bước 1: Gán Max:=A[1];
Bước 2: Nếu Max<A[2] thì gán Max:=A[2];
Bước 3: Nếu Max<A[3] thì gán Max:=A[3];
...
Bước n: Nếu Max<A[n] thì gán Max:=A[n];
Khởi đầu, Max được gán giá trị A[1]. Sang bước 2, Max được so sánh với
A[2] để chọn ra số lớn nhất giữa A[1], A[2] và lưu vào biến Max. Sang bước
3, Max được tiếp tục so sánh với A[3] để tìm ra số lớn nhất giữa A[1], A[2],
A[3], .v.v. Kết qủa, sau bước n, biến Max sẽ chứa số lớn nhất của dãy A[1],
A[2], ..., A[n].
Quá trình trên được mô tả bằng hai lệnh:
Max:=A[1];
For i:=2 to n do if Max<A[i] then Max:=A[i];
Nhận xét:
Trong lệnh For trên, biến i chạy bắt đầu từ 2, nhưng kết qủa vẫn đúng
nếu cho i chạy bắt đầu từ 1.
Không nhất thiết phải gán giá trị ban đầu cho Max là A[1], mà có thể
gán cho Max một phần tử tùy ý trong mảng, ví dụ phần tử A[n] chẳng hạn,
nhưng khi đó biến i trong lệnh For phải chạy bắt đầu từ 1.
Ví dụ 10.3: Bài toán sắp xếp mảng tăng dần (hay giảm dần)
Cho dãy A[1], A[2],..., A[n], nói rằng A là một dãy tăng nếu A[1]
A[2] ... A[n], tương tự, A là dãy giảm nếu A[1] A[2] ... A[n].
Dãy đồng nhất A[1]=A[2]= ... =A[n] là trường hợp đặc biệt, vừa là dãy tăng,
vừa là dãy giảm.
Ví dụ:
Dãy 1 3 3 5 5 6 6 6 là dãy tăng
Dãy 9 9 8 5 5 4 0 0 là dãy giảm
Dãy 1 3 3 2 5 4 6 6 là dãy không tăng không giảm.
Bài toán đặt ra là: cho một dãy A[1], A[2], ..., A[n] bất kỳ, hãy thực hiện
các hoán đổi các gía trị của các phần tử trong mảng A để A lập thành một
dãy tăng.
Ví dụ, cho dãy A có 5 phần tử A[1]=9, A[2]=7, A[3]=5, A[4]=8, và A[5]=
2, cần thực hiện các hoán đổi như thế nào để có A[1]=2, A[2]=5, A[3]=7,
A[4]=8 và A[5]=9.
Có những phương pháp sắp xếp mảng khác nhau, ở đây chỉ xin giới thiệu
một phương pháp, tuy chưa phải là hay nhưng đơn giản và dễ hiểu cho
những người mới lập trình, đó là phương pháp lựa chọn trực tiếp (Straight
selection sort).
Ý tưởng của phương pháp là như sau:
Bước 1: Tìm số nhỏ nhất trong các phần tử A[1], A[2],.., A[n] và để vào
vị trí đầ? tiên A[1].
Bước 2: Tìm số nhỏ nhất trong các phần tử A[2], A[3],.., A[n] và để vào
vị trí thứ hai A[2].
.v.v.
Bước n-1: Tìm số nhỏ nhất trong hai phần tử A[n-1], A[n] và để vào vị trí
n-1. Sau bước này thì A[n] sẽ là gía trị lớn nhất.
Chẳng hạn, xét dãy A có 4 phần tử: {5,3,4,1}:
Bước 1: Nếu A[1]>A[2] thì đổi A[1] với A[2], được: {3,5,4,1}
Nếu A[1]>A[3] thì đổi A[1] với A[3]: không đổi
Nếu A[1]>A[4] thì đổi A[1] với A[4], được: {1,5,4,3}
Bước 2: Nếu A[2]>A[3] thì đổi A[2] với A[3], được: {1,4,5,3}
Nếu A[2]>A[4] thì đổi A[2] với A[4], được: {1,3,5,4}
Bước 3: Nếu A[3]>A[4] thì đổi A[3] với A[4], được: {1,3,4,5}
Sau ba bước, dãy A đã được sắp xếp xong.
Tại bước thứ i (i chạy từ 1 đến 3 ), ta phải so sánh A[i] lần lượt với A[j] (j
chạy từ i+1 đến 4), nếu A[i]>A[j] thì hoán đổi các gía trị của A[i] và A[j],
nói cho gọn là đổi chỗ A[i] với A[j]. Qúa trình trên được thể hiện bằng hai
vòng lặp For :
For i:=1 to 3 do
For j:=i+1 to 4 do
if A[i]>A[j] then Ðổi chỗ A[i] và A[j] ;
Mảng A ở trên chỉ có 4 phần tử, trong trường hợp tổng quát khi mảng A
có N phần tử thì lệnh For thứ nhất sẽ có biến i chạy từ 1 đến N-1, và lệnh
For thứ hai sẽ có biến j chạy từ i+1 đến N, tức là :
For i:=1 to N-1 do
For j:=i+1 to N do
if A[i]>A[j] then Ðổi chỗ A[i] và A[j] ;
Việc đổi chỗ các gía trị trong A[i] và A[j] được tiến hành bằng cách dùng
một biến Z trung gian cùng kiểu dữ liệu với A[i] và A[j]. Ðầu tiên gởi tạm
gía trị của A[i] vào biến Z, sau đó đưa gía trị của A[j] vào A[i], và cuối cùng
đưa gía trị trong Z vào A[j], tức là phải làm ba lệnh :
Z:=A[i];
A[i]:=A[j];
A[j]:=Z;
Tóm lại, thuật toán sắp xếp dãy A tăng được viết như sau:
For i:=1 to N-1 do
For j:=i+1 to N do
if A[i]>A[j] then
begin { Ðổi chỗ A[i] và A[j] }
Z:=A[i];
A[i]:=A[j];
A[j]:=Z;
end;
Trong đó N là số phần tử của dãy A còn Z là một biến trung gian có cùng
kiểu dữ liệu với các phần tử của mảng A.
Chương trình dưới đây tìm số lớn nhất của mảng A và sắp dãy A tăng
dần:
PROGRAM VIDU103;
{ Tìm Max và sắp dãy A tăng dần }
Uses CRT;
Type
Kmang = array[1..20] of Real;
Var
i, j, N : Integer;
A: Kmang;
z, Max : Real;
Begin
Clrscr;
Repeat
Write(‘ Nhập số phần tử N : ‘);
Readln(N);
Until (N>0) and ( N<21);
For i:=1 to N do { nhập mảng }
begin
Write(‘Nhập A[‘, i, ‘]: ‘);
Readln(A[i]);
end;
{ Tìm số lớn nhất }
Max :=A[1];
For i :=1 to N do if Max< A[i] then Max:=A[i];
Writeln(‘ Số lớn nhất là: ’ , Max : 4:1);
{ sắp xếp dãy tăng }
For i:=1 to N-1 do
For j:=i+1 to N do
If A[i]>A[j] then {23}
begin { đổi chỗ A[i] và A[j] }
z:=A[i];
A[i]:=A[j];
A[j]:=z;
end;
Writeln(‘ Dãy đã sắp xep tăng là : ‘);
For i:=1 to N do Write(A[i]:3:0);
Readln;
End.
Chạy
Chép tập tin nguồn
Chú ý 1: Muốn sắp dãy A giảm dần thì trong chương trình trên chỉ cần
thay dòng {23}:
If A[i] > A[j] then ...
bằng dòng :
If A[i] < A[j] then ...
Tức là thay dấu lớn hơn > bằng dấu nhỏ hơn < .
Chú ý 2 : Sắp xếp một bộ phận của dãy.
Gọi m và h là hai số nguyên sao cho 1<= m< h<= N, khi đó A[m],
A[m+1], ..., A[h] là một dãy con của dãy A. Muốn sắp dãy con A[m],
A[m+1], ..., A[h] tăng (hay giảm) mà không làm ảnh hưởng đến các phần
còn lại của dãy A, ta dùng lệnh sau:
For i:= m to h-1 do
For j:=i+1 to h do
if A[i]>A[j] then
begin { Ðổi chỗ A[i] và A[j] }
Z:=A[i];
A[i]:=A[j];
A[j]:=Z;
end;
Ví dụ 10.4: Kiểm tra mảng có thỏa một tính chất không.
Ta thường gặp bài toán kiểm tra xem mọi phần tử của mảng A có thỏa
mãn một điều kiện không, ví dụ mảng A có phải là dãy tăng không, có phải
là dãy đối xứng không, có phải là một cấp số cộng không, ...
Mảng A thỏa tính chất đang xét nếu mọi phần tử của nó thỏa một điều
kiện xác định nào đó, ngược lại, mảng A không thỏa tính chất đang xét nếu
có một phần tử của nó không thỏa điều kiện này.
Hai trạng thái thỏa hay không thỏa được thể hiện bằng hai gía trị TRUE
hay FALSE của một biến Kiemtra kiểu lôgic. Ðầu tiên ta gán giả định
Kiemtra:= TRUE, sau đó ta xét từng phần tử của A, chỉ cần có một phần tử
không thỏa điều kiện thì gán ngay Kiemtra:=FALSE . Vậy hai lệnh cần dùng
là:
Kiemtra:=TRUE;
For i:=1 to N do
if A[i] không thỏa điều kiện then Kiemtra:= FALSE;
Việc xác định điều kiện là tùy từng bài toán cụ thể.
Ví dụ: Kiểm tra xem A có phải là một dãy đối xứng không ?
Dãy 1 3 5 4 5 3 1 là đối xứng.
Dãy 1 3 5 4 2 3 1 là không đối xứng vì A[3] khác A[5].
Như vậy, dãy N phần tử A1, A2, ..., An là đối xứng nếu A1=An, A2=An-1, ...,
An=A1, tức Ai = An-i+1 với mọi i=1, 2, ..., n. Ðẳng thức : Ai = An-i+1 chính là
điều kiện mà mọi phần tử của dãy A phải thỏa để A là một dãy đối xứng.
Giả thiết biến Kiemtra đã được khai báo kiểu Boolean. Trong chương
trình ta dùng các lệnh sau:
Kiemtra:=TRUE;
For i:=1 to N do
if A[i]A[N-i+1] then Kiemtra:=FALSE;
If Kiemtra=TRUE then writeln(‘ Dãy A đối xứng’)
else
Writeln( ‘Dãy A không đối xứng ‘);
Trong thuật toán trên, lệnh For có thể thay bằng lệnh While, tốc độ sẽ
nhanh hơn song cũng khó hiểu hơn:
Kiemtra:=TRUE;
i:=1;
While ( i <=N ) and ( Kiemtra=TRUE) do
if A[i]A[N-i+1] then Kiemtra:=FALSE
else i:=i+1;
If Kiemtra=TRUE then writeln(‘ Dãy A đối xứng’)
else Writeln( ‘Dãy A không đối xứng ‘);
Bạn đọc hãy viết chương trình cho ví dụ này.
Chú ý Câu lệnh :
If Kiemtra=TRUE then writeln(‘ Dãy A đối xứng’)
else Writeln( ‘Dãy A không đối xứng ‘);
hoàn toàn tương đương với lệnh :
If Kiemtra then writeln(‘ Dãy A đối xứng’)
else Writeln( ‘Dãy A không đối xứng ‘);
Ví dụ 10.5: Tính gía trị của đa thức :
P = ao + a1x + a2x2 + ... + anxn
trong đó số nguyên n, số thực x và các hệ số a0, a1, ..., an được nhập từ bàn
phím.
Ta viết :
P= aoU0 + a1U1 + a2U2 + ... + anUn , trong đó :
U0=1;
Ui = xi = xi-1 *x = Ui-1*x với i=1,2, ..., N
Như vậy, nếu tính được gía trị U ở bước i-1 thì sẽ tính được gía trị U ở
bước i bằng lệnh U:= U*x, sau đó ta chỉ việc cộng dồn biểu thức ai*U vào P
bằng lệnh P:= P+ ai*U.
Chương trình được viết như sau :
PROGRAM VIDU105;
{ Tính gía trị của đa thức bậc N }
Var
i, N : Integer;
A: Array[0..20] of Real;
x, P, U : Real;
Begin
Repeat
Write(‘ Nhập N và x : ‘);
Readln(N, x);
Until (N>0) and ( N<21);
For i:=0 to N do { nhập mảng các hệ số}
begin
Write(‘Nhập hệ số A[‘, i, ‘]: ‘);
Readln(A[i]);
end;
U:=1;
P:=A[0];
For i:=1 to N do
begin
U:=U*x;
P:=P+A[i]*U;
end;
Writeln(‘ P=‘, P:6:2);
Readln;
End.
Chạy
Chép tập tin nguồn
Các file đính kèm theo tài liệu này:
- mang_mot_chieu_2674.pdf