I. KIỂU LIỆT KÍ, KIỂU MIỀN CON
2. Kiểu miền con (Sub-range type) a Khâi niệm
a. Khâi niệm
Khi khai bâo một số trường hợp, ví dụ Tuổi của người hoặc Ðiểm thi học sinh, nếu ta viết: VAR
Hay Diem : Real ; {Real có miền xâc định 2.9 E-39 .. 1.7 E38}
Nếu viết như vậy sẽ tốn ô nhớ vì Integer có kích thước 2 bytes hoặc Real có kích thước đến 6 bytes. Lăm như vậy sẽ không cần thiết vì Tuổi con người chỉ biến thiín trong khoảng từ 0 đến 200 lă lớn nhất vă điểm thi học sinh thì chỉ trong khoảng từ 0 đến 10 chẳng hạn.
Trong Pascal cho phĩp ta xâc định một biến lấy giâ trị trong một khoảng năo đó được giới hạn ở một hằng cận dưới (first data item) vă một hằng cận trín (last data item). Hai giâ trị năy phải cùng một kiểu vô hướng đếm được vă hằng cận trín có giâ trị lớn hơn hằng cận dưới. Khai bâo như vậy gọi lă khai bâo kiểu miền con (Sub-range type) vă biến của nó chỉ chiếm 1 byte trong ô nhớ mă thôi. Trong lúc chạy chương trình, ta có thể kiểm tra giâ trị của biến không được vượt ra khỏi giới hạn của khoảng con.
b. Câch khai bâo
Miền con lă một tập hợp con của một kiểu đếm được. Có 2 câch khai bâo:
+ Khai bâo giân tiếp: TYPE
<Tín kiểu miền con> = <hằng cận dưới> .. <hằng cận trín> ; VAR
<danh sâch biến> : < Tín kiểu miền con> ; Ví dụ 8.5:
TYPE
TuoiTho = 0 .. 200 ; VAR Tho : TuoiTho ;
+ Khai bâo trực tiếp: VAR
<danh sâch biến> : <hằng cận dưới> .. <hằng cận trín> ; Ví dụ 8.6:
VAR Tuoi : 0 .. 200 ;
II. KIỂU MẢNG, KIỂU CHUỖI
Pascal có 4 kiểu cấu trúc dữ liệu lă kiểu mảng (ARRAY), tập hợp (SET), bản ghi (RECORD) vă tập tin (FILE). Sau đđy ta lần lượt tìm hiểu từng kiểu cấu trúc.
1. Dữ liệu kiểu mảng (Array-Type Data)
Một mảng dữ liệu lă một tập hợp số hữu hạn phần tử có giống như câc biến, có cùng kiểu, gọi lă kiểu cơ bản.
Mảng được được tổ chức theo một trật tự xâc định. Số phần tử của mảng được khai bâo ngay từ khi định nghĩa ra mảng.
a. Mảng một chiều (One-Dimensional Array)
Mảng một chiều có thể được hiểu như một danh sâch câc phần tử (theo cột), có cùng kiểu. Mỗi phần tử của mảng được xâc định được truy nhập trực tiếp thông qua tín mảng cùng với chỉ dẫn truy nhập được để giữa hai ngoặc vuông [ ].
Ví dụ 8.7:
List lă một mảng 1 chiều có n phần tử. Câc phần tử của List có thể mang câc tín List[1], List[2], List[3], ..., List[n], vă có thể minh họa như hình sau:
List[1] List[2] List[3] List[4] ... List[n] Hình 8.1: Minh họa mảng một chiều
+ Khai bâo giân tiếp:
TYPE
<Kiểu mảng> = ARRAY [Kiểu chỉ số ] OF <Kiểu phần tử > ; VAR
<Danh sâch biến> : Kiểu mảng ;
+ Khai bâo trực tiếp :
VAR
< Danh sâch biến > : ARRAY [ Kiểu chỉ số] OF < Kiểu phần tử > ; * Chú ý: Kiểu chỉ số phải lă kiểu rời rạc (đếm được).
Ví dụ 8.8:
TYPE
KM1 = ARRAY [1.. 100] OF INTEGER ; KM2 = ARRAY [1 .. 20 ] OF CHAR ;
DAY = (Sun, Mon, Tue, Wed, Thu, Fri, Sat) ; VAR
TUOI : KM1 ; TEN : KM2 ;
Ý nghĩa:
- KM1 lă kiểu mảng gồm 100 phần tử được đânh số từ 1 đến 100 thông qua kiểu chỉ dẫn lă một miền con câc số nguyín từ 1 .. 100. TUOI lă biến có kiểu lă KM1.
- KM2 lă kiểu mảng gồm 20 phần tử đânh số từ 1 .. 20 có kiểu lă câc ký tự. Biến TEN có kiểu lă KM2.
- NGAY lă một biến mảng gồm 7 phần tử kiểu Boolean được đânh dấu qua kiểu chỉ dẫn lă tín của 7 ngăy trong tuần.
Chú ý:
Khi khai bâo mảng, kiểu chỉ dẫn chỉ có thể lă:
- Kiểu miển con của câc loại dữ liệu vô hướng đếm được như ký tự, số nguyín - Kiểu liệt kí do người viết định nghĩa (như NGAY trong tuần)
- Kiểu Boolean
Kiểu chỉ dẫn không thể lă kiểu không đếm được như REAL Viết như sau lă SAI : X1 : ARRAY [Real] OF Integer ;
Ta cũng không thể khai bâo như: X2 : ARRAY [Integer] OF Integer ;
Mặc dầu Integer lă kiểu vô hướng đếm được do giới hạn của vùng nhớ dănh cho dữ liệu, số lượng phần tử của 1 mảng cũng bị hạn chế tùy theo kích thước của kiểu dữ liệu của câc phần tử, ta nín dùng kiểu miền con để khai bâo số phần tử của mảng.
+ Truy xuất câc phần tử của mảng:
Mỗi phần tử của mảng được truy xuất thông qua Tín Biến Mảng cùng với chỉ số của mảng trong dấu ngoặc vuông [ ]. Ví dụ tín biến mảng lă A, khi viết A[7], ta hiểu nó lă phần tử thứ 7 của mảng A.
Ví dụ 8.9: Lập trình giải một băi toân tính trung bình một dêy số x[i] : x[1], x[2], x[3], ... , x[n]
sau đó tiếp tục tính độ lệch (deviation) của từng phần tử so với trị trung bình, theo công thức: độ_lệch = x[i] - trung_bình
Giả sử dêy số của chúng ta có giới hạn n = 100 phần tử trở lại, n lă một biến số để khai bâo số phần tử muốn tính . Sau đó ta lần lượt nhập tính giâ trị của phần tử kiểu số thực (real) từ phần tử thứ 1 đến phần tử thứ n. Trong chương trình sẽ tạo ra một mảng 1 chiều x với n câc phần tử. Tính trung bình của n phần tử vă độ lệch. In kết quả ra măn hình.
PROGRAM Average_deviations ;
{ Nhập n số phần tử kiểu số thực, tính trị trung bình của chúng, sau đó tính tiếp độ lệch của từng phần tử số so với trị trung bình }
n, count : integer ;
sum, average, deviation : real ; x : ARRAY [1 .. 100] OF real ; BEGIN
(* Nhập số phần tử vă tính trung bình*)
Write (' Nhập bao nhiíu số n để tính trung bình ? ') ; Readln (n) ; Writeln ; sum := 0 ; FOR count := 1 TO n DO BEGIN Write ( ‘ i = ‘, count : 3, ‘ x = ‘ ) ; Readln (x [count] ) ;
sum := sum + x[count]; END ;
average := sum/n ;
Writeln (' Trung bình của dêy số lă = , average ') ; Writeln ;
(* Tính độ lệch so với trị trung bình *) FOR count := 1 TO n DO
BEGIN
deviation := x[count] - average ;
Write ( ‘ i = ‘, count : 3, ‘ x = ‘, x[count] ) ; Writeln (' Ðộ lệch d = , deviation ');
END ; Readln; END.
x[1] = 3.0 x[2] = -2.0 x[3] = 12.0 x[4] = 4.4 x[5] = 3.5 Khi chạy chương trình (nhấn Ctrl + F9), trín măn hình ta sẽ thấy : Nhập bao nhiíu số n để tính trung bình ? 5
i = 1 x = 3.0
i = 2 x = -2.0
i = 3 x = 12.0
i = 4 x = 4.4
i = 5 x = 3.5
Trung bình của dêy số lă = 4. 1800000E+00
i = 1 x = 3. 0000000E+00 Ðộ lệch d = - 1. 1800000E+00 i = 2 x = -2. 0000000E+00 Ðộ lệch d = - 6. 1800000E+00 i = 3 x = 1. 2000000E+00 Ðộ lệch d = 7. 8200000E+00 i = 4 x = 4. 4000000E+00 Ðộ lệch d = 2. 2000000E - 01 i = 5 x = 3. 5000000E+00 Ðộ lệch d = - 6. 8000000E - 01 Ta có thể định khoảng chừa kết quả vă phần lẻ thập phđn, dùng lệnh : m : n Ví dụ 8.10: Sắp xếp một dêy số theo thứ tự từ nhỏ đến lớn
Tiến trình của băi toân:
- Giả sử chuỗi số của ta có n phần tử . Lần lượt cho chương trình đọc giâ trị của câc phần tử nhập được.
- Một thủ tục (Procedure) sẽ lăm công việc sắp xếp như sau : đầu tiín đưa phần tử thứ nhất so sânh với câc phần tử tiếp theo, nếu nó lớn hơn phần tử so sânh thì đem đổi chổ giâ trị của hai phần tử với nhau. Sau đó tiếp tục đem phần tử thứ 2 so sânh câc phần tử tiếp theo theo trình tự như vậy, ... vă cứ như thế cho đến phần tử thứ n - 1.
- In kết quả ra măn hình Chương trình Pascal như sau: PROGRAM Reorder ;
(* Sắp xếp một mảng câc phần tử số thực từ nhỏ đến lớn*) VAR n, i, loc: 1 .. 100 ;
x : ARRAY [1 .. 100] OF real ; temp : real ;
PROCEDURE interchange ;
(* Ðổi chỗ câc phần tử mảng từ nhỏ đến lớn*) BEGIN
FOR loc := 1 TO n-1 DO
FOR i := loc + 1 TO n DO IF x[i] < x [loc] THEN
BEGIN temp := x[loc] ; x[loc] := x[i] ; x[i] := temp ; END ; END ; BEGIN
Write (' Có bao nhiíu phần tử số ? ') ; Readln (n) ; FOR i := 1 TO n DO BEGIN Write ( ‘ x[ ‘, i : 3, ‘] = ? ‘ ) ; Readln( x[i] ) ; END ; interchange ; Writeln ;
Writeln (' Số liệu đê sắp xếp : ') ; Writeln ;
FOR i := 1 TO n DO
Writeln ( ‘x[ ‘, i : 3, ‘ ] = ‘, x[i] : 4 : 1 ) ; Readln;
END.
(câc số có gạch dưới lă phần nhập từ băn phím) Có bao nhiíu phần tử số ? 5 x[ 1] = ? 4. 7 x[ 2] = ? - 2. 3 x[ 3] = ? 12. 9 x[ 4] = ? 8. 8 x[ 5] = ? 6. 0 Kết quả lă : Số liệu đê sắp xếp : x[ 1] = ? - 2. 3 x[ 2] = ? 4. 7 x[ 3] = ? 6. 0 x[ 4] = ? 8. 8 x[ 5] = ? 12. 9
b. Mảng nhiều chiều (Multi-Dimensional Array)
Trong một số băi toân thực tế, người ta sử dụng câc mảng nhiều hơn 1 chiều, gọi lă mảng nhiều chiều.
Ví dụ 8.11: Phòng Ðăo tạo quản lý điểm của sinh viín. Trong khoâ 22 chẳng hạn, người ta tạo ra một mảng 2 chiều: ví dụ một chiều lă số thứ tự của sinh viín, chiều còn lại lă câc môn học (dạng kiểu vô hướng liệt kí), ta có thể hình dung dạng của mảng ghi điểm (tín mảng lă ghi_diem) như sau:
Lưu ý: Thực tế, danh sâch tín sinh viín lưu lại trong mây tính thường được ghi bằng câch gân mê số sinh viín (coding) cho mỗi sinh viín ngay từ năm đầu văo học.
Với ví dụ trín, muốn nhập điểm một sinh viín năo đó ta phải khai bâo 2 tham số lă số thứ tự sinh viín vă môn học.
Tương tự, cũng với câc khoâ kế tiếp theo học những môn như vậy, ta sẽ tạo ra mảng nhiều chiều như hình vẽ minh họa sau:
Trong trường hợp năy, muốn biết điểm một sinh viín năo đó ta phải khai bâo 3 tham số: Khoâ học, số thứ tự sinh viín vă môn học, chẳng hạn:
ghi_diem[K22,0001,AV] nhập điểm 10,... Khai bâo cũng có 2 câch như đối với mảng 1 chiều:
+ Khai bâo giân tiếp:
TYPE
<Kiểu mảng> = ARRAY [Kiểu_chỉ_số_1, ..., Kiểu_chỉ_số_n] OF <Kiểu phần tử>;
VAR
<Danh sâch biến>:<Kiểu mảng>; Ví dụ 8.12:
TYPE matrix = ARRAY [1 .. 20, 1 .. 30] OF integer ; VAR A:matrix;
Lệnh trín khai bâo một kiểu tín matrix. Ðđy lă một mảng 2 chiều, chiều thứ nhất có câc chỉ số từ 1 đến 20, chiều thứ hai có câc chỉ số từ 1 đến 30, tổng cộng ta có (20 x 30) phần tử số nguyín. Vă ta có một biến A lă biến có kiểu matrix.
Ví dụ trín cũng có thể được khai bâo tương đương với:
TYPE matrix = ARRAY [1 .. 20] OF ARRAY [1 .. 30] OF integer ; VAR A:matrix;
+ Khai bâo giân tiếp:
VAR
Khai bâo một biến A có 5 dòng vă 10 cột kiểu phần tử lă Integer như sau: VAR A : ARRAY [1 .. 5, 1 .. 10] OF integer ;
+ Truy xuất câc phần tử mảng:
Tương tự như câch truy xuất phần tử của mảng 1 chiều, mảngg nhiều chiều cũng được truy xuất thông qua tín biến mảng kết hợp với câc chỉ số của nó được đặt trong cặp dấu ngoặc vuông.
Mảng 2 chiều lă một ma trận, như ví dụ trín ta có một ma trận 5 dòng vă 10 cột. Câc phần tử của ma trận A được ký hiệu lă a[i,j] với i lă vị trí cột vă j lă dòng. Khi viết a[2, 7] thì hiểu đđy lă phần tử ở dòng 2 vă cột 7.
Trong Pascal, ta có thể viết a[i,j] thănh a[i] [j] với ý nghĩa hoăn toăn như nhau.
Chú ý: Trín nguyín tắc, ta có thể khai bâo một mảng có đến 255 chiều. Tuy vậy, một điều cần lưu ý lă kích thước bộ nhớ của mây tính có hạn nín thường chỉ khai bâo mảng từ 1 đến 3 chiều. Khai biến quâ nhiều thì phải cần mây lớn hơn.
Chẳng hạn khi bâo 1 mảng [1.. 10] câc phần tử số nguyín đê lấy 10 bytes bộ nhớ - Mảng 2 chiều 10 x 10 = 100 bytes bộ nhớ. - Mảng 3 chiều 10 x 10 x 10 = 1 000 bytes bộ nhớ - Mảng 4 chiều 10 x 10 x 10 x 10 = 10 000 bytes bộ nhớ - Mảng 5 chiều 10 x 10 x 10 x 10 x 10 = 100 000 bytes bộ nhớ - v.v... Ví dụ 8.13:
Viết một chương trình Pascal để đọc một bảng câc số thực được nhập văo mây tính dưới dạng một mảng 2 chiều. Tính tổng câc giâ trị số theo hăng vă theo cột. Kết quả được in ra măn hình theo vị trí hăng vă cột tương ứng.
Trước tiín, ta bắt đầu bằng định nghĩa câc biến:
table = mảng 2 chiều chứa số thực dưới dạng bảng gồm câc số nhập vă kết quả nrows = một biến số nguyín chỉ số hăng
ncols = một biến số nguyín chỉ số cột row = một số đếm nguyín chỉ số hăng col = một số đếm nguyín chỉ số cột
Ðể đơn giản, chúng ta giả sử rằng kích thước số liệu nhập văo bảng tính không vượt quâ 10 hăng vă 10 cột. Ta sẽ thím văo 1 hăng cộng phía dưới vă 1 cột cộng bín phải văo bảng để ghi kết quả tính cộng câc phần tử hăng vă cột tương ứng. Như vậy, mảng 2 chiều của chúng ta sẽ trở thănh mảng sẽ được in ra có số hăng lă (nrows + 1) vă số cột lă (ncols +1). Do vậy, ta phải khai bâo biến table lă 1 mảng 2 chiều số nguyín có tối đa 11 cột vă 11 hăng.
Ðể dễ theo dõi chương trình, ta thực hiện cấu trúc module khi viết chương trình bằng câch tiến hănh lăm câc thủ tục procedure cho đọc số liệu, tính tổng câc phần tử theo hăng, tính tổng câc phần tử theo cột vă in ra măn hình bảng kết quả. Câc thủ tục năy sẽ có tín tương ứng lă readinput, rowsums, columsums vă writeoutput.
Thuật toân logic yíu cầu cho mỗi thủ tục lă câch khai bâo thẳng trước (straightforward), chú ý rằng trong mỗi thủ tục ta có một vòng lặp đôi (double loop). Ví dụ, để đọc số liệu ở bảng gốc, ta sẽ phải lăm một vòng lặp đôi sau:
FOR row := 1 TO nrows DO BEGIN
FOR col := 1 TO ncols DO readln( table[row, col] ) ; Writeln;
END ;
Cđu lệnh Writeln để bâo chương trình nhảy tới dòng kế.
Tương tự, vòng lặp sau được viết để tính tổng câc phần tử theo hăng: FOR row := 1 TO nrows DO
BEGIN
table [row, ncols + 1] := 0 ; FOR col := 1 TO ncols DO
table [row, ncols + 1] := table [row, ncols + 1] + table [row, col]; END ;
Tương tự, cấu trúc vòng lặp đôi cũng được dùng để tính tổng câc phần tử cột vă in ra bảng kết quả cuối cùng.
Sau đđy lă chương trình Pascal của băi toân trín: PROGRAM Tongbang ;
{đọc một bảng số, tính tổng từng cột vă hăng của câ bảng} VAR
row, col : 1 .. 11 ; nrows, ncols : 1 .. 10 ;
table : ARRAY [1 .. 11, 1 .. 11] OF real ;
PROCEDURE Rowsums ; {cộng câc phần tử theo cột bín trong mỗi hăng } BEGIN
FOR row := 1 TO nrows DO BEGIN
table [row,ncols+1] := 0 ; FOR col := 1 TO ncols DO
table[row, ncols+1] := table[row, ncols+1] + table[row,col]; END ;
END ;
PROCEDURE Columnsums ; {cộng câc phần tử theo hăng bín trong từng cột } BEGIN
FOR col := 1 TO ncols DO BEGIN
table [nrows+1, col] := 0 ; FOR row := 1 TO nrows DO
table[nrows+1,col] := table[nrows+1,col] + table[row,col]; END ;
END ;
PROCEDURE Readinput ; {đọc câc phần tử của bảng } BEGIN
Write(' Nhập số hăng (1 .. 10) ? ') ;Readln(nrows) ; Write(' Nhập số cột (1 .. 10) ? ') ;Readln(ncols) ; FOR row := 1 TO nrows DO
BEGIN
Writeln (' Nhập số liệu hăng số , row :2') ;
FOR col := 1 TO ncols DO readln(table [row, col] ) ; END ;
END ;
PROCEDURE Writeoutput ; { In ra bảng số liệu vă kết quả tính tổng } BEGIN
Writeln('Bảng số liệu vă kết quả tính tổng câc phần tử theo hăng vă cột '); Writeln(‘============================================= ‘); Writeln;
FOR row := 1 TO nrows + 1 DO BEGIN
FOR col := 1 TO ncols+1 DO Write (table [row,col] : 6 : 1) ; Writeln; END ; END ; BEGIN { Thđn chương trình chính } Readinput ; Rowsums ; Columnsums ; Writeoutput; END. { Chấm dứt chương trình } Giả sử, ta có bảng số liệu sau :
2.5 -6.3 14.7 4.0 10.8 12.4 -8.2 5.5 10.8 12.4 -8.2 5.5 -7.2 3.1 17.7 -9.1
Khi chạy chương trình, ta có (số có gạch dưới lă số của người thử chương trình): Nhập số hăng (1 .. 10 ) ? 3 Nhập số cột (1 .. 10) ? 4 Nhập số liệu hăng số 1 2.5 -6.3 14.7 4.0 Nhập số liệu hăng số 2 10.8 12.4 -8.2 5.5 Nhập số liệu hăng số 3 -7.2 3.1 17.7 -9.1
Chương trình sẽ tính tổng câc giâ trị ở hăng vă cột, xong in ra măn hình kết quả: Bảng số liệu vă kết quả tính tổng câc phần tử theo hăng vă cột
2.5 -6.3 14.7 4.0 14.9 10.8 12.4 -8.2 5.5 20.5 10.8 12.4 -8.2 5.5 20.5 -7.2 3.1 17.7 -9.1 4.5 6.1 9.2 24.2 0.4 0.0 Ta có thể kiểm tra kết quả ở câc hăng vă cột. 2. Dữ liệu kiểu chuỗi (String Type Data)
Một chuỗi dữ liệu lă một loạt câc ký tự được định nghĩa bằng từ khoâ STRING theo sau lă số ký tự cực đại có thể có của chuỗi ký tự. String lă một kiểu cấu trúc được thím văo trong Turbo Pascal. a. Khai bâo
Chúng ta có thể khai bâo kiểu chuỗi ký tự String giân tiếp hoặc trực tiếp. Khai bâo giân tiếp lă khai kiểu trước rồi sau đó mới khai bâo biến. Câch khai bâo trực tiếp lă khai thẳng biến số. Chiều dăi tối đa của chuỗi ký tự phải lă một hằng nguyín vă được đặt trong dấu ngoặc vuông [ ]. Trường hợp không khai bâo thì chương trình sẽ lấy giâ trị mặc nhiín lă 255 ký tự