Vui lòng download xuống để xem tài liệu đầy đủ.

Khai báo và sử dụng danh sách liên kết trong Pascal

Chia sẻ: | Ngày: | Loại File: pdf | 15 trang

0
289
lượt xem
79
download

Danh sách liên kết đơn Danh sách là một dãy hữu hạn các phần tử thuộc cùng một lớp đối tượng nào đó. Ví dụ : danh sách sinh viên, danh sách vật tư, danh sách các hoá đơn, danh sách các số thực. Trong các bài trước ta đã dùng mảng để biểu thị một danh sách. Cách này có các nhược điểm: kích thước của mảng phải định trước nên tốn bộ nhớ (số phần tử thực tế dùng nhiều khi rất ít so với khai báo), khi thêm một phần tử vào mảng hoặc xoá một...

Khai báo và sử dụng danh sách liên kết trong Pascal
Nội dung Text

  1. Khai báo và sử dụng danh sách liên kết trong Pascal 1. Danh sách liên kết đơn Danh sách là một dãy hữu hạn các phần tử thuộc cùng một lớp đối tượng nào đó. Ví dụ : danh sách sinh viên, danh sách vật tư, danh sách các hoá đơn, danh sách các số thực. Trong các bài trước ta đã dùng mảng để biểu thị một danh sách. Cách này có các nhược điểm: kích thước của mảng phải định trước nên tốn bộ nhớ (số phần tử thực tế dùng nhiều khi rất ít so với khai báo), khi thêm một phần tử vào mảng hoặc xoá một phần tử ra khỏi mảng ta phải mất nhiều thời gian để dồn mảng. Danh sách liên kết dùng để cài đặt một danh sách sẽ khắc phục được các nhược điểm trên của mảng. Danh sách liên kết thuận gồm nhiều phần tử nằm không liên tục trong Heap. Cấu tạo của danh sách liên kết thuận: có một con trỏ first chứa địa chỉ của phần tử đầu tiên của danh sách, phần tử đầu có phần dữ liệu và một con trỏ next để chứa địa chỉ của phần tử thứ hai, tổng quát phần tử thứ i có phần dữ liệu và một con trỏ next để chứa địa chỉ của phần tử thứ i+1, đối với phần tử cuối cùng giá trị của con trỏ next bằng NIL. Để thuận tiện khi thêm phần tử mới vào cuối danh sách liên kết ta dùng một con trỏ last chứa địa chỉ của phần tử cuối cùng. Khởi tạo một danh sách rỗng first = NIL Chương trình Dslk.pas minh hoạ các cách làm việc với danh sách liên kết thuận. Phần dữ liệu của một phần tử là các thông tin về một sinh viên. USES crt; TYPE SVienPtr = ^SVien; SVien = RECORD maso: STRING[6]; hoten: STRING[23]; dtb: REAL; next: SVienPtr END; VAR first, last: SVienPtr; chon: BYTE; traloi: CHAR;
  2. PROCEDURE Bosung; VAR p: SVienPtr; ans: INTEGER; BEGIN WHILE TRUE DO BEGIN new(p); WITH p^ DO BEGIN write('Ma sinh vien : '); readln(maso); write('Ho va ten : '); readln(Hoten); write('Diem trung binh: '); readln(dtb); END; p^.next:=NIL; IF first=NIL THEN BEGIN first:= p; last:= p END ELSE BEGIN last^.next:= p; last:= p END; write('Co tiep tuc khong 1/0 ? '); readln(ans); IF ans=0 THEN break; END; END; PROCEDURE DuyetXuoi; VAR p: SVienPtr; BEGIN IF first = NIL THEN BEGIN writeln('D.sach rong'); exit END; p := first; WHILE p <> NIL DO
  3. BEGIN WITH p^ DO writeln(maso:5,' ',Hoten:25,' ',dtb:5:2); p := p^.Next; END; END; PROCEDURE ChenSau; VAR q,p: SVienPtr; found: BOOLEAN; masv: STRING[6]; BEGIN IF first <> NIL THEN BEGIN write('Ma so SV can tim de chen : '); readln(masv); p:= first; found:= FALSE; WHILE (p<>NIL) AND (NOT found) DO IF p^.maso=masv THEN found := TRUE ELSE p:=p^.next; IF found THEN BEGIN new(q); WITH q^ DO BEGIN write(' Ma so : '); readln(maso); write(' Ho ten : '); readln(Hoten); write(' Diem trung binh : '); readln(dtb); END; q^.next:= p^.next; p^.next:= q; END ELSE BEGIN write('Khong tim thay'); readln END; END; END; PROCEDURE TimXoa;
  4. VAR masv: STRING[6]; found: BOOLEAN; p,q: SVienPtr; BEGIN write('Ma so SV can loai khoi danh sach : '); readln(masv); p:= first; IF p<>NIL THEN BEGIN found:= FALSE; WHILE (p<>NIL) AND (NOT found) DO IF p^.maso=masv THEN found := TRUE ELSE BEGIN q:=p; p:=p^.next END; IF found THEN BEGIN IF p=first THEN first :=p^.next ELSE q^.next:=p^.next; IF p^.next=NIL THEN last:=q; dispose(p) END ELSE BEGIN write('Khong tim thay'); readln END; END; END; BEGIN clrscr; First := NIL; REPEAT writeln; writeln('1. Bo sung mot sinh vien'); writeln('2. Duyet danh sach sinh vien');
  5. writeln('3. Tim kiem mot phan tu va chen vao sau'); writeln('4. Tim kiem mot phan tu va xoa'); writeln('5. Ket thuc chuong trinh'); writeln; write('Chon chuc nang: '); readln(chon); writeln; CASE chon OF 1: Bosung; 2: DuyetXuoi; 3: ChenSau; 4: TimXoa; END; UNTIL chon=5; WHILE first<>NIL DO BEGIN last:= first; first:= first^.next; dispose(last) END; END. 2. Danh sách liên kết kép Danh sách liên kết kép là danh sách mà mỗi phần tử của nó gồm ba thành phần: phần dữ liệu, con trỏ next chứa địa chỉ phần tử tiếp sau, con trỏ prev chứa địa chỉ của phần tử liền trước, con trỏ next của phần tử cuối cùng trong danh sách bằng NIL, con trỏ prev của phần tử đầu tiên cũng bằng NIL. Danh sách liên kết kép hoàn toàn xác định bởi hai con trỏ: con trỏ firstchứa địa chỉ phần tử đầu tiên, con trỏ last chứa địa chỉ phần tử cuối cùng. Danh sách liên kết kép cho phép dễ dàng xác định phần tử đứng trước một phần tử đã biết, do đó nó thuận tiện hơn danh sách liên kết thuận trong các thao tác: duyệt ngược danh sách, chèn một phần tử mới vào trước một phần tử, xoá một phần tử. Chương trình DslkKep.pas minh hoạ cách làm việc với danh sách liên kết kép. USES crt; TYPE svienPtr = ^svien;
  6. svien = RECORD maso : STRING[6]; hoten: STRING[23]; dtb : REAL; prev, next : svienPtr; END; VAR first,last: svienPtr; chon: BYTE; PROCEDURE Bosung; VAR p,q: svienPtr; ans: CHAR; BEGIN WHILE TRUE DO BEGIN new(p); WITH p^ DO BEGIN write('- Ma so: '); readln(maso); write('- Ho va ten: '); readln(hoten); write('- Diem trung binh: '); readln(dtb); END; IF first=NIL THEN BEGIN p^.next:= NIL; p^.prev := NIL; first:= p; last:= p; END ELSE BEGIN q:= last; q^.next:= p; p^.next:= NIL; p^.prev:= q; last:= p; END; write('Co tiep tuc khong C/K ?'); readln(ans); IF upcase(ans) = 'K' THEN break;
  7. END; END; PROCEDURE DuyetXuoi; VAR p: svienPtr; BEGIN IF first <> NIL THEN BEGIN p:= first; WHILE p<> NIL DO BEGIN WITH p^ DO writeln(maso,' ',hoten,' ',dtb:1:2); p:= p^.next; END; END ELSE writeln('Danh sach rong '); readln; END; PROCEDURE DuyetNguoc; VAR p: svienPtr; BEGIN IF first <> NIL THEN BEGIN p:= last; WHILE p<> NIL DO BEGIN WITH p^ DO writeln(maso,' ',hoten,' ',dtb:1:2); p:= p^.prev; END; END ELSE writeln('Danh sach rong '); readln; END; PROCEDURE ChenTruoc;
  8. VAR p,q,r: svienPtr; found: BOOLEAN; masv: STRING[6]; BEGIN write('Ma so SV can tim : '); readln(masv); IF first<>NIL THEN BEGIN p:= first; found:= FALSE; WHILE (p<>NIL) AND (NOT found) DO IF p^.maso=masv THEN found := TRUE ELSE p:=p^.next; IF found THEN BEGIN new(q); WITH q^ DO BEGIN write('- Ma so: '); readln(maso); write('- Ho va ten: '); readln(hoten); write('- Diem trung binh: '); readln(dtb); END; IF p=first THEN BEGIN q^.next:= p; first^.prev:= q; first:= q END ELSE BEGIN r:=p^.prev; q^.next:= r^.next; r^.next:= q; q^.prev:= p^.prev; p^.prev:= q END; END ELSE BEGIN write('Khong tim thay'); readln END; END;
  9. END; PROCEDURE TimXoa; VAR p,q,pt: svienPtr; found: BOOLEAN; masv: STRING[6]; BEGIN write('Ma so SV can loai khoi danh sach : '); readln(masv); IF first<>NIL THEN BEGIN p:= first; found:= FALSE; WHILE (p<>NIL) AND (NOT found) DO IF p^.maso=masv THEN found := TRUE ELSE p:=p^.next; IF found THEN BEGIN q:= p^.prev; pt:= p^.next; IF q<>NIL THEN q^.next:= p^.next; IF pt<>NIL THEN pt^.prev:= p^.prev; IF p=first THEN first:= pt; IF p=last THEN last:= q; dispose(p); END ELSE BEGIN write('Khong tim thay '); readln END; END; END; BEGIN first:= NIL; clrscr; REPEAT writeln('1. Bo sung phan tu'); writeln('2. Duyet danh sach theo chieu xuoi'); writeln('3. Duyet danh sach theo chieu nguoc'); writeln('4. Chen vao truoc mot phan tu'); writeln('5. Tim kiem va xoa mot phan tu');
  10. writeln('6. Ket thuc chuong trinh'); write(' Chon chuc nang : '); readln(chon); CASE chon OF 1: Bosung; 2: DuyetXuoi; 3: DuyetNguoc; 4: ChenTruoc; 5: TimXoa; END; UNTIL chon=6; WHILE first<> NIL DO BEGIN last:=first; first:=first^.next; dispose(last); END; END. 3. Ngăn xếp dùng danh sách liên kết Stack là một danh sách theo đó tất cả các công việc chèn và huỷ đều được thực hiện ở một đầu của danh sách (gọi là đỉnh của ngăn xếp). Stack giống như một chồng đĩa, đĩa nào đặt cuối cùng lên đỉnh chồng thì đĩa đó sẽ được lấy ra đầu tiên. Do đó Stack còn có tên gọi là LIFO (last in first out – vào sau ra trước). Việc thêm một phần tử vào stack có tên gọi là đẩy (Push) vào stack, còn việc huỷ một phần tử khỏi stack gọi là lấy (Pop) khỏi stack. Stack dùng danh sách liên kết hoàn toàn giống danh sách liên kết thuận, nhưng chỉ có điều khác là khi thêm phần tử mới hay huỷ một phần tử ta luôn luôn làm ở đầu danh sách. Do đó ta phải duy trì một con trỏ Top để trỏ vào phần tử đầu tiên của danh sách (đỉnh của stack) Chương trình StDslk.pas minh hoạ cách làm việc với stack dùng danh sách liên kết, các phần tử của stack là các số nguyên dương. USES crt; TYPE StackPtr= ^node; node = RECORD data: INTEGER; next: StackPtr;
  11. END; VAR top: StackPtr; chon,n: INTEGER; PROCEDURE Push(n: INTEGER); VAR p: StackPtr; BEGIN new(p); p^.data:= n; p^.next:= top; top:= p; END; FUNCTION Pop: INTEGER; VAR p: StackPtr; BEGIN IF top=NIL THEN pop:=0 ELSE BEGIN pop:= top^.data; p:= top; top:= top^.next; dispose(p) END; END; PROCEDURE Duyet; VAR p: StackPtr; BEGIN IF top<>NIL THEN BEGIN p:=top; WHILE p<>NIL DO BEGIN writeln(p^.data,' '); p:=p^.next END; END ELSE
  12. writeln('Stack rong'); readln; END; BEGIN clrscr; top:=NIL; REPEAT write('1. Push 2. Pop 3. Duyet 4. Thoat. Chon: '); read(chon); CASE chon OF 1: BEGIN write('Vao n : '); readln(n); Push(n) END; 2: BEGIN n:= Pop; IF n<>0 THEN writeln('Phan tu lay ra = ',n) ELSE writeln('Stack rong'); END; 3: Duyet; END; UNTIL chon=4; END. 4. Hàng đợi dùng danh sách liên kết Queue là một danh sách mà việc thêm một phần tử mới được thực hiện ở đuôi queue, việc huỷ một phần tử được thực hiện ở đầu queue. Queue giống như một dãy khách hàng xếp hàng trả tiền trong siêu thị, người xếp hàng trước sẽ được phục vụ trước và ra khỏi hàng, người mới tham gia xếp hàng thì xếp vào cuối hàng. Do đó queue còn có tên gọi FIFO (first in first out – vào trước thì ra trước). Queue dùng danh sách liên kết hoàn toàn giống danh sách liên kết thuận , nhưng chỉ có điều khác là khi thêm phần tử mới ta luôn luôn nối vào cuối danh sách, khi huỷ một phần tử ta luôn huỷ phần tử đầu tiên trong danh sách. Do đó ta phải duy trì hai con trỏ: front trỏ vào phần tử đầu, back trỏ vào phần tử cuối
  13. Chương trình QueDslk.pas tạo một hàng đợi gồm các số nguyên dương dùng danh sách liên kết thuận. USES crt; TYPE queuePtr= ^node; node = RECORD data: INTEGER; next: queuePtr; END; VAR front,back: queuePtr; chon,n: INTEGER; PROCEDURE ThemVao(n: INTEGER); VAR p: queuePtr; BEGIN new(p); p^.data:= n; p^.next:= NIL; IF front=NIL THEN BEGIN front:=p; back:=p END ELSE BEGIN back^.next:=p; back:=p END; END; FUNCTION LayRa: INTEGER; VAR p: queuePtr; BEGIN IF front=NIL THEN LayRa:=0 ELSE BEGIN LayRa:= front^.data; p:= front;
  14. front:= front^.next; dispose(p) END; END; PROCEDURE Duyet; VAR p: queuePtr; BEGIN IF front<>NIL THEN BEGIN p:=front; WHILE p<>NIL DO BEGIN write(p^.data,' '); p:=p^.next END; writeln; END ELSE writeln('Queue rong'); readln; END; BEGIN clrscr; front:=NIL; back:=NIL; REPEAT write('1.Push 2.Pop 3.Duyet 4.Thoat. Chon: '); read(chon); CASE chon OF 1: BEGIN write('Vao n : '); readln(n); ThemVao(n) END; 2: BEGIN n:= LayRa; IF n<>0 THEN writeln('Phan tu lay ra = ',n) ELSE
  15. writeln('Queue rong'); END; 3: Duyet; END; UNTIL chon=4; END.
Đồng bộ tài khoản