1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Lập trình bằng Turbo Pascal part 8 pdf

28 393 1
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 28
Dung lượng 293,69 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Duyệt một danh sách lμ thao tác truy cập đến tất cả các phần tử của danh sách để thực hiện một xử lí nμo đó sao cho đảm bảo không sót vμ không lặp.. Một danh sách các hồ sơ được thực hi

Trang 1

Duyệt một danh sách lμ thao tác truy cập đến tất cả các phần tử của

danh sách để thực hiện một xử lí nμo đó sao cho đảm bảo không sót vμ không

lặp Không sót nghĩa lμ mọi phần tử đều được xử lí, không lặp nghĩa lμ

không phần tử nμo bị xử lí quá một lần

Phép duyệt có thể thực hiện nhờ một vòng lặp For

For i:= 1 to L.kt do " xử lí L.PhanTu[i]" ;

Ví dụ

Thay toμn bộ tên bằng chữ in hoa

For i:= 1 to L.kt do L.PhanTu[i]:= upper(L.PhanTu[i]);

Tìm kiếm

Tìm kiếm một phần tử trong danh sách lμ nhằm phát hiện phần tử có chứa một thμnh phần dữ liệu trùng khớp với mẫu đã cho Mẫu nμy thường

được gọi lμ khóa tìm kiếm

Tuỳ theo danh sách có được sắp xếp thứ tự theo khoá đã cho hay

không mμ có các cách tìm kiếm khác nhau

Tìm kiếm tuần tự - Sequential Searching

Khi danh sách chưa được sắp xếp thì cách duy nhất để thực hiện tìm kiếm lμ duyệt từ đầu, cho đến khi tìm thấy hoặc phát hiện không có

Tìm kiếm nhị phân - Binary Searching

Khi danh sách đã được sắp xếp đúng thứ tự theo khoá cần tìm thì có thể tiến hμnh tìm kiếm theo cách chia đôi dần Đây lμ thủ tục tìm kiếm nhị phân đã xét đến trong phần thủ tục đệ quy

Thêm phần tử

- Hoặc nối vμo cuối, khi đó danh sách không được sắp theo thứ tự Thực hiện đơn giản nhưng sẽ phải chi phí nhiều khi tìm kiếm

- Hoặc chèn đúng chỗ, theo cách nμy buộc phải tìm đúng vị trí vμ sau

đó dịch chuyển cả phần đuôi Thực hiện phức tạp hơn nhưng bù lại khi tìm kiếm sẽ nhanh hơn

Gỡ bỏ phần tử

- Tìm đến phần tử cần gỡ bỏ vμ huỷ phần tử nμy bằng cách chép dồn lên

1.4 Các ưu, nhược điểm

Danh sách thể hiện bằng cấu trúc mảng có các ưu nhược điểm sau

Trang 2

- Đơn giản, có thể cμi đặt đễ dμng bằng kiểu mảng đã quen biết

- Bất tiện khi thường xuyên có thao tác thêm bớt phần tử ở giữa danh sách

1.5 Ví dụ minh hoạ

Để thấy được các ưu nhược điểm của danh sách mảng hãy cải tiến chương trình quản lí hồ sơ của sinh viên đã phát triển trong chương 3

Chương trình nμy đã cho phép tiến hμnh các thao tác tạo lập, liệt kê, tìm kiếm

vμ thêm một hồ sơ vμo cuối danh sách Cần bổ xung thêm chức năng thứ 5

lμ cho phép huỷ một hồ sơ

1.5.1 Phân tích, thiết kế

Chức năng huỷ một hồ sơ trong danh sách sinh viên lμ thủ tục phức

tạp hơn cả vì bản ghi cần huỷ có thể nằm ở giữa tệp Cần có thao tác dồn lấp chỗ trống Nội dung tệp phải viết lại hoμn toμn Do đó cần đọc toμn bộ thông tin ra một mảng trong bộ nhớ để tiện xử lí Chỉ viết lại vμo tệp ở thời điểm cuối cùng, khi mọi thay đổi đã hoμn tất

Một danh sách các hồ sơ được thực hiện bằng mảng các bản ghi Ta cần khai báo một danh sách mảng như sau

Type DSHoso = Record

PhanTu: array [1 max_kt] of Hoso;

- Đầu vμo: tệp đã mở sẵn, mã số của hồ sơ cần huỷ gõ từ bμn phím

- Đầu ra: tệp không còn chứa bản ghi cần huỷ

Chi tiết dần từng bước

5.1 Chép toμn bộ nội dung tệp ra mảng các bản ghi

5.2.1 Đưa cửa sổ tệp về đầu tệp; gán chỉ số đầu tiên của mảng

5.2.2 Đọc từ tệp ra phần tử mảng 5.2.3 Tăng chỉ số mảng lên một 5.2.4 Dừng khi hết tệp

5.2 Nhập mã số của hồ sơ cần huỷ

5.3 Tìm kiếm phần tử mảng lμ bản ghi có mã số đã cho:

5.3.1 Gọi thủ tục Tìm kiếm

5.4 Xử lí kết quả tìm kiếm

5.4.1 Trường hợp không thấy, hiển thị thông báo không thấy

Trang 3

5.4.2 Trường hợp thấy, tiến hμnh gỡ bỏ bản ghi khỏi mảng:

5.4.2.1 Chép dồn các phần tử mảng lên một vị trí lấp vμo chỗ phần tử mảng bị gõ bỏ,

1.5.2 Triển khai chi tiết

Từ bảng phân tích chi tiết dần từng bước ở trên, dễ dμng chuyển thμnh một thủ tục Pascal như dưới đây Lưu ý rằng để nhấn mạnh cấu trúc danh

sách vμ dễ theo dõi ta không sử dụng câu lệnh with mμ viết đầy đủ các cấp

của kiểu bản ghi lồng nhau

{chep lai vao danh sach de xu ly thao tac huy}

while not eof(TepHoso) do

TimThay:= false; i:= 0;

while (not TimThay) do

Trang 4

L.PhanTu[i].namsinh:= L.PhanTu[i+1].namsinh; end

Trang 5

TenMC[2]:=' Tim kiem ';

TenMC[3]:=' Them vao ';

2 Danh sách kiểu ngăn xếp - Stack

Nếu các thao tác thêm bớt phần tử không xảy ra "ở giữa" danh sách thì hoμn toμn có thể thực hiện bằng mảng như đã phân tích ở trên Dưới đây xét hai loại danh sách đặc biệt, các phép thêm vμo, lấy ra thực hiện tại vị trí

đầu hoặc cuối

2.1 Định nghía danh sách kiểu ngăn xếp

Khi lμm việc với một chồng hồ sơ trên bμn, ta chỉ thấy được cái trên cùng, lấy ra lần lượt từ trên xuống dưới Nếu có thêm hồ sơ mới thì xếp

chồng lên trên Mô hình trừu tượng hoá của chồng hồ sơ chính lμ một danh sách với các thao tác thêm vμo, lấy ra chỉ thực hiện tại đầu danh sách Đó lμ

danh sách kiểu ngăn xếp hay Stack

Đinh nghĩa: Danh sách kiểu ngăn xếp (Stack) lμ một kiểu danh sách

tuyến tính đặc biệt mμ phép thêm vμo, lấy ra phần tử chỉ thực hiện ở một đầu

gọi lμ đỉnh ngăn xếp - Top

Trang 6

Khi có thao tác lấy ra thì phần tử được xếp cuối cùng vμo ngăn xếp sẽ

được lấy ra đầu tiên Do đó ngăn xếp còn có tên gọi lμ danh sách kiểu last in,

first out hay danh sách LIFO

Stack có rất nhiều ứng dụng

Hình 13.1: Một ngăn xếp các hồ sơ

2.2 Biểu diễn danh sách kiểu ngăn xếp

Như đã phân tích ở cuối tiết trước, danh sách kiểu ngăn xếp có thể

đươc thực hiện dễ dμng bằng mảng Một ngăn xếp gồm một biến mảng các phần tử vμ một biến kiểu số nguyên để ghi số phần tử hiện có Nếu đánh số các phần tử mảng từ 1 thì số phần tử hiện có đồng thời cũng lμ chỉ số của phần tử trên cùng của mảng Kiểu ngăn xếp có thể được khai báo như sau

Type NganXep = Record

PhanTu: array [1 max_kt ] of kiểu phần tử ;

2.3 Các phép toán đối với kiểu ngăn xếp

1 - Khởi tạo ngăn xếp rỗng: Top:= 0;

2 - Thêm vμo một phần tử

Tên chuẩn lμ Push Các bước thực hiện lμ

Trang 7

- Kiểm tra đầy ngăn xếp chưa Nếu đầy, báo lỗi “trμn ngăn xếp”

- Trái lại: sửa lại vị trí đỉnh vμ chép phần tử mới vμo

Procedure Push(x: kiểuphầntử, VAR S:NgănXếp);

begin if S.Top=maxSize then

Tên chuẩn lμ Pop Các bước thực hiện lμ

- Kiểm tra ngăn xếp có rỗng không Nếu rỗng, báo lỗi “ ngăn xếp

rỗng”

- Trái lại: lấy ra nội dung phần tử ở đỉnh vμ sửa lại vị trí đỉnh

Procedure Pop(S: NgănXếp; VAR x: kiểuphầntử) ;

begin if Top=0 then

3 Danh sách kiểu hàng đợi - Queue

3.1 Định nghĩa danh sách kiểu hàng đợi

Kiểu danh sách hμnh đợi lμ mô hình hóa một loại danh sách mμ hoạt

động của nó giống như hμng đợi trước cửa một quầy bán vé Phần tử mới chỉ

được thêm vμo cuối còn phần tử được lấy ra chỉ từ vị trí đầu tiên của danh sách

Định nghĩa: Danh sách kiểu hμng đợi (Queue) lμ một kiểu danh sách

mμ:

- Phép thêm phần tử vμo chỉ thực hiện ở một đầu mút, gọi lμ lối sau

(rear) hay đuôi hμng đợi;

- Phép lấy phần tử ra thực hiện ở đầu kia, gọi lμ lối trước (front) hay

đầu hμng đợi

Trang 8

←←←←←

front rear

Hình 13.2: Hμng đợi trước quầy bán vé

Danh sách kiểu hμng đợi sẽ hoạt động theo theo nguyên tắc, đến trước

phục vụ trước, đến sau phục vụ sau do đó còn có tên gọi lμ danh sách kiểu

first in first out hay danh sách FIFO

3.2 Biểu diễn danh sách kiểu hàng đợi bằng mảng

Hμng đợi Q gồm một biến mảng chứa các phần tử, hai biến kiểu số

nguyên để ghi chỉ số của phần tử đầu vμ phần tử cuối vμ một biến nguyên

khác để ghi số phần tử hiện có

Type HangDoi = Record

PhanTu: array [0 max_kt - 1] of kiểuphầntử ; r,f, kt: word;

end;

Var Q: HangDoi;

Trong đó, max_kt lμ kích thước lớn nhất (dự phòng) có thể của hμng đợi r =

chỉ số phần tử cuối hμng đợi, f = chỉ số phần tử đầu hμng đợi, kt = số phần

tử hiện có

Lưu ý việc đánh chỉ số các phần tử mảng bắt đầu bằng 0 để thuận tiện

hơn cho việc nối vòng tròn như sau nμy sẽ thấy

- Khi thêm một phần tử vμo hμng đợi cần tăng chỉ số phần tử cuối r

lên 1 vμ chép nội dung vμo Q(r):

Trang 9

Thêm vμo: kt:= kt+ 1; r:=r+1; Q[r]:=x ;

- Khi lấy một phần tử ra khỏi hμng đợi cần đọc nội dung Q(f) vμ tăng

f lên 1:

Lấy ra: x:= Q[f]; f:= f+1; kt:= kt -1;

Tuy nhiên, nếu theo dõi hoạt động của hμng đợi sau một loạt thao tác

thêm vμo, lấy ra được triển khai đơn giản như trên sẽ có hiện tượng hμng đợi

“bò trườn”, di chuyển dần đi trong bộ nhớ

Để khắc phục hiện tượng nμy cần hạn chế một vùng nhớ, chỉ cho mảng

các phần tử xoay trở trong vùng nμy Giải pháp lμ nối đầu đuôi thμnh vòng

tròn Do đó phải sử dụng phép chia đồng dư modulo trong tính toán các chỉ

- Nối vòng tròn khi thêm vμo

Nếu r = max_kt -1 thì r+1 vượt ra ngoμi mảng Cần lộn trở lại đầu

mảng như hình vẽ, tức lμ cần có r+1:= 0 Công thức tính vị trí của phần tử

đuôi phải thay đổi lại lμ

r:= (r+1) Mod max_kt

- Nối vòng tròn khi lấy ra

Khi lấy ra, địa chỉ f của đầu hμng đợi cũng cộng thêm 1 Do đó, vấn

Trang 10

Procedure Enqueue(x: kiểuphầntử; VAR Q: HangDoi );

begin if Q.kt = max_kt then “bao loi tran”

Muốn thực hiện một danh sách với thao tác thêm bớt phần tử một cách thuận tiện tại bất cứ vị trí nμo ta cần khắc phục nhược điểm của cách tổ chức xếp liên tiếp các phần tử bằng cách dùng con trỏ để móc nối, sử dụng liên kết

động Khi thêm vμo phần tử hoặc lấy ra phần tử chỉ cần sủa lại các liên kết

Một danh sách móc nối cấu tạo từ các nút - node Mỗi nút gồm tối

thiểu hai trường:

Trang 11

- Data: chứa dữ liệu hoặc con trỏ đến biến động chứa dữ liệu;

Next: con trỏ trỏ tới nút tiếp theo

-

Nút cuối cùng của danh sách có trường Next = NIL

Như vậy, mỗi nút lμ một biến kiểu bản ghi - record, có một trường

kiểu con trỏ trỏ đến một nút để lμm mối nối

4.2.2 Khai báo kiểu danh sách móc nối

Có một điểm tế nhị cần lưu ý lμ khi khai báo trường kiểu con trỏ trỏ

đến một nút thì chính kiểu nút còn chưa được định nghĩa xong Theo quy

định chung thì mọi thứ như hằng, kiểu, biến, hμm, thủ tục đều phải được

định nghĩa trước khi sử dụng, nghĩa lμ sau dấu con trỏ (^) phải lμ kiểu dữ liệu

đã được định nghĩa

Pascal chấp nhận một biệt lệ cho trường hợp nμy Trong khai báo kiểu mới ta có thể sử dụng một kiểu chưa được định nghĩa rồi định nghĩa nó sau, miễn lμ cùng nằm trong phần khai báo kiểu

Khi xây dựng danh sách móc nối ta phải khai báo trước kiểu mối nối

nutPtr lμ con trỏ đến một nút vμ sau đó mới khai báo kiểu nút

Một danh sách L được truy cập bằng 1 con trỏ tới nút đầu tiên Danh sách rỗng thì L = NIL

Type nutPtr = ^nut;

Nut = Record

End;

Type DanhSachMocNoi = nutPtr;

Hình dưới đây minh hoạ một danh sách móc nối L

L

DC

B

A

Hình 13.5: Hình ảnh của một danh sách móc nối

Trang 12

4.3 Các phép toán

Tại một thời điểm chỉ có thể truy cập đến một nút trong danh sách Đó lμ

nút hiện hμnh hay View Trong các thao tác đối với danh sách, cần có con trỏ

không bỏ sót nút nμo gọi lμ duyệt danh sách

Procedure DS_Duyet(VAR L: DanhSachMocNoi);

Trang 13

- Nếu L rỗng thì nút thêm vμo lμ đầu danh sách

- Trái lại, cần phải sửa hai mối nối như hình vẽ

L V

Hình 13.6: Móc nối lại để thêm nút vμo sau View

Procedure DS_ThemNut_SauView(x: kiểudữliệu;

VAR L: DanhSachMocNoi; V: nutPtr);

- Dò từ đầu danh sách đến nút ngay trước V, sau đó thêm vμo sau nút nμy

- Hoặc dùng thủ thuật, chép nội dung Data của V vμo N, chép nội dung

Data mới vμo V, sửa lại các mối nối giống như trong thủ tục trên (Hãy tự

thực hiện như một bμi tập)

N

Trang 14

- Trái lại, có hai cách lμm

1 - Dò từ đầu danh sách đến nút ngay trước V, sửa mối nối của nút nμy, cho trỏ đến nút sau V

2 - Dùng thủ thuật sau: Nếu V không phải lμ nút cuối danh sách thì

chép nội dung Data của nút sau V vμo nút V, sửa mối nối của V cho trỏ đến

nút sau nữa Nếu V lμ nút cuối danh sách thì phức tạp hơn Phải dò tìm từ

đầu danh sách đến nút ngay trước V vμ sửa mối nối của nút nμy thμnh NIL

(Hãy tự thực hiện như một bμi tập)

Thủ tục dưới đây thực hiện theo cách 1

Procedure DS_HuyNut(VAR L:DanhSachMocNoi ; V:nutPtr);

con trỏ đến nút cuối danh sách T = Tail để tiện thao tác Trong trường hợp

nμy một danh sách móc nối lμ bộ 2 con trỏ: L trỏ đến đầu danh sách vμ T trỏ

đến nút cuối cùng

5 Danh sách nối kép

5.1 Cấu trúc danh sách nối kép

Danh sách nối đơn chỉ tiện khị duyệt theo một chiều Nếu cần duyệt theo chiều ngược lại thì chi phí lớn

Trang 15

Cải tiến, thực hiện thêm mối nối theo chiều ngược lại Một nút có hai con trỏ, trỏ đến nút sau vμ đến nút trước nó

Left Data Right

L R

d c

Khai báo cấu trúc một nút nut vμ kiểu danh sách nối kép cũng tương

tự như trường hợp danh sách nối đơn

Type nutPtr = ^ nut;

Nut = Record

Data: kiểu dữ liệu;

Left, Right: nutPtr;

End;

Type DSNoiKep = nutPtr;

5.2 Các phép toán với danh sách nối kép

Phép khởi tạo danh sách rỗng lμ khởi tạo các con trỏ L, R bằng NIL Các thao tác duyệt vμ tìm kiếm có thể triển khai dễ dμng theo hai chiều

Ta xét các thao tác thêm nút vμ gỡ bỏ nút

1 -Thêm nút

Cần xét 3 trường hợp

- khi danh sách rỗng

- khi bổ sung vμo vi trí cực trái (cực phải);

- khi bổ xung vμo giữa danh sách

Trường hợp bổ xung vμo giữa danh sách cần chia thμnh thêm vμo bên trái nút hiện hμnh V vμ thêm vμo bên phải nút hiện hμnh V

Trang 16

Procedure DS2_ThemNutVaoTraiView(x: kiÓud÷liÖu;

VAR L:DSNoiKep V: nutPtr);

else if V = L then { bæ xung vμo cùc tr¸i }

begin Nˆ.Left:= NIL; Nˆ.Right:=V; Vˆ.Left:=N; L:=N;

- khi lo¹i nót cùc tr¸i (cùc ph¶i);

- khi lo¹i nót ë gi÷a

Procedure DS2_HuyNut(VAR L: DSNoiKep; V: nutPtr);

begin if L= NIL then “danh s¸ch rçng ”

else if L=R then L:=R:=NIL

else if V=L then begin L:=Lˆ.Right; Lˆ.Left:= NIL end else if V=R then begin R:=Rˆ.Left; Rˆ.Right:= NIL end else

begin (Vˆ.Left)ˆ.Right:= Vˆ.Right;

Trang 17

6 Ví dụ ứng dụng của danh sách móc nối

6.1 Cải tiến chương trình quản lí hồ sơ

Lại xét bμi toán quản lí hồ sơ của sinh viên Ta đã xây dựng một

chương trình quản gồm có các chức năng tạo lập, liệt kê, tìm kiếm, thêm vμo

cuối vμ huỷ một hồ sơ khỏi danh sách Vì chưa sử dụng con trỏ vμ biến động,

thực hiện danh sách bằng mảng nên thao tác thêm bản ghi chỉ thuận tiện nếu thực hiện tại cuối danh sách Thao tác huỷ một bản ghi đòi hỏi phải chép dồn toμn bộ phần đuôi danh sách rất vất vả khi danh sách có nhiều phần tử

Để có thể tiến hμnh các thao tác chèn thêm, gỡ bỏ các bản ghi một cách thuận tiện thì cách tốt nhất lμ liên kết các bản ghi bằng một cấu trúc

danh sách động - danh sách móc nối

Ta hãy thử xây dựng một chương trình cải tiến hơn, không dùng danh sách mảng mμ sử dụng danh sách móc nối để giải quyết bμi toán trên

Chương trình có các chức năng mở tệp, liệt kê, tìm kiếm vμ sửa chữa thông tin, thêm một hồ sơ vμ huỷ một hồ sơ của danh sách Với tính linh hoạt của danh sách móc nối, có thể dễ dμng thực hiện chức năng chèn thêm hồ sơ vμ huỷ hồ sơ tại một vị trí bất kì trong danh sách Do đó có thể tổ chức danh sách được sắp theo thứ tự

6.2 Phân tích thiết kế

6.2.1

6.2.2

Cấu trúc dữ liệu

Sử dụng cấu trúc danh sách móc nối đơn như đã trình bμy trên Phần

dữ liệu trong mỗi nút lμ một bản ghi kiểu HoSo

Type nutPtr = ^nut;

nut = Record

Data: HoSo;

next: nutPtr;

end;

Type DanhSachMocNoi = nutPtr;

Để cho xác định, ta quy ước sắp xếp danh sách theo mã số sinh viên tăng dần

Thực thi các chức năng

Thủ tục mở tệp không có gì thay đổi

Các chương trình con thực hiện các chức năng khác của chương trình

như liệt kê, tìm kiếm, thêm vμo vμ gỡ bỏ hồ sơ sẽ gọi các phép toán tương ứng

trên danh sách móc nối Do đó phần đầu của chương trình lμ phần triền khai

Ngày đăng: 23/07/2014, 21:20

HÌNH ẢNH LIÊN QUAN

Hình 13.1: Một ngăn xếp các hồ sơ - Lập trình bằng Turbo Pascal part 8 pdf
Hình 13.1 Một ngăn xếp các hồ sơ (Trang 6)
Hình 13.6: Móc nối lại để thêm nút vμo sau View. - Lập trình bằng Turbo Pascal part 8 pdf
Hình 13.6 Móc nối lại để thêm nút vμo sau View (Trang 13)

TỪ KHÓA LIÊN QUAN