Danh sách nối kép (double link list)

Một phần của tài liệu Bài giảng môn Cấu Trúc Dữ Liệu và Thuật toán doc (Trang 37 - 41)

* Với danh sách móc nối đơn và nối vòng, chỉ có phép duyệt 1 chiều, từ phần tử trước có thể truy nhập đến phần tử đứng sau, nhưng từ phần tử đứng sau không truy cập trực tiếp đến phần tử đứng ngay trước nó được. Khắc phục hạn chế này ta có danh sách liên kết kép

* Mỗi phần tử trong danh sách nối kép là một nút (bản ghi) gồm 3 trường: - Info : chứa thông tin về đối tượng.

- LPTR : con trỏ trỏ tới phần tử bên trái - RPTR : con trỏ trỏ tới phần tử bên phải

+ Quy cách một node:

+ Hình ảnh danh sách móc nối đối có dạng:

Để truy nhập các phần tử của d/s ta có thể truy cập xuất phát từ một trong hai đầu của danh sách. Do đó, ta quản lý danh sách bằng cách dùng 2 con trỏ L, R lần lượt trỏ tới node cực trái, phải của danh sách. Khi đó d/s rỗng nếu: L=R= nill

A B C D

L

LPTR INFO RPTR

A B C D

L R

Hình 2.4 – hình ảnh danh sách liên kết đơn vòng

(Tương tự như danh sách móc nối đơn, với danh sách nối kép, ta cũng có các phép toán tác động tương ứng)

* Một số phép toán:

1) Phép bổ sung một phần tử (vào trước phần tử trỏ bởi con trỏ M)

(Giải thuật: Bạn đọc tự viết)

2) Phép loại bỏ 1 phần tử ra khỏi danh sách nối kép

+ Giả sử ta có một d/s nối kép, có 2 nút cực trái, cực phải là L, R. loại bỏ nút trỏ

bởi con trỏ M ra khỏi danh sách

(Chú ý: trong nhiều bài toán cụ thể: Yêu cầu, nút cần loại bỏ là nút thoả mãn điều kiện nào đó, khi đó ta phải di chuyển con trỏ M trỏ đến nút đó )

38 A B C D L M R E × × (1) (4) (3) (2) q

Nếu danh sách rồng (L = R = nil):

Ghép nối {L := R := q; q^ . LPtr := nil; q^ . RPtr := nil; Nếu danh sách khác rỗng : {q^ . LPtr := M^. LPtr; q^ .RPtr := M; M^. LPtr := q; q^ .LPtr^. RPtr := q; (1) (2) (3) (4) A B C D L (1) M R (1) Hình 2.6 – Thêm một phần tử ở vị trí trước M

Hình 2.6 – Loại bỏ một phần tử ở vị trí MNếu danh sách rỗng: (L = R = nil): Return Loại bỏ: Nếu : {L := L^. RPtr ; L^ . LPtr := nil ; Nếu : M =L : {M^. PPtr^. LPtr := M^. LPtr; M^. LPtr^. RPtr := M^. Rptr ; (1) (2) {R:= R^. LPtr ; R^ . RPtr := nil ; Nếu : M =R :

+ Giải thuật: Dành cho bạn đọc

2.1.3.3. So sánh hai phương pháp cài đặt danh sách bởi mảng và bởi con trỏ

Không thể kết luận phương pháp cài đặt nào hiệu quả hơn, mà nó hoàn toàn tuỳ thuộc vào từng ứng dụng hay tuỳ thuộc vào các phép toán trên danh sách. Tuy nhiên ta có thể tổng kết một số ưu nhược điểm của từng phương pháp làm cơ sở để lựa chọn phương pháp cài đặt thích hợp cho từng ứng dụng:

- Cài đặt bằng mảng đòi hỏi phải xác định số phần tử của mảng, do đó nếu không thể ước lượng được số phần tử trong danh sách thì khó áp dụng cách cài đặt này một cách hiệu quả vì nếu khai báo thiếu chỗ thì mảng thường xuyên bị đầy, không thể làm việc được còn nếu khai báo quá thừa thì lãng phí bộ nhớ.

- Cài đặt bằng con trỏ thích hợp cho sự biến động của danh sách, danh sách có thể rỗng hoặc lớn tuỳ ý chỉ phụ thuộc vào bộ nhớ tối đa của máy. Tuy nhiên ta phải tốn thêm vùng nhớ cho các con trỏ (trường link).

- Cài đặt bằng mảng thì thời gian xen hoặc xoá một phần tử tỉ lệ với số phần tử đi sau vị trí xen/ xóa. Trong khi cài đặt bằng con trỏ các phép toán này mất chỉ một hằng thời gian.

- Phép truy nhập vào một phần tử trong danh sách, chẳng hạn như PREVIOUS, chỉ tốn một hằng thời gian đối với cài đặt bằng mảng, trong khi đối với danh sách cài đặt bằng con trỏ ta phải tìm từ đầu danh sách cho đến vị trí trước vị trí của phần tử hiện hành.Nói chung danh sách liên kết thích hợp với danh sách có nhiều biến động, tức là ta thường xuyên thêm, xoá các phần tử. (adsbygoogle = window.adsbygoogle || []).push({});

2.2 Ngăn xếp (Stack) và ứng dụng2.2.1. Định nghĩa ngăn xếp 2.2.1. Định nghĩa ngăn xếp

? Cho biết ưu khuyết điểm của danh sách đặc và danh sách liên kết ? Ưu khuyết điểm của các loại danh sách liên liên kết

- Ngăn xếp (Stack) là một danh sách đặc biệt, trong đó việc thêm vào hoặc loại bỏ một phần tử chỉ thực hiện tại một đầu của danh sách, đầu này gọi là đỉnh (TOP) của ngăn xếp.

Ví dụ: Ta có thể xem hình ảnh trực quan của ngăn xếp bằng một chồng đĩa đặt trên bàn. Muốn thêm vào chồng đó 1 đĩa ta để đĩa mới trên đỉnh chồng, muốn lấy các đĩa ra khỏi chồng ta cũng phải lấy đĩa trên trước.

Như vậy ngăn xếp là một cấu trúc có tính chất “vào sau - ra trước” hay “vào trước – ra sau“ (LIFO (last in - first out ) hay FILO (first in – last out)).

- Hình ảnh của ngăn xếp có dạng như sau:

2.2.2 Các phép toán cơ bản trên ngăn xếp:

1- MAKENULL_STACK(S): tạo một ngăn xếp rỗng.

2- POP(S,x) chương trình con lấy một phần tử tại đỉnh ngăn xếp S lưu vào biến x .

3 - PUSH(x,S) chương trình con thêm một phần tử x vào đầu ngăn xếp. 4 - EMPTY_STACK(S) kiểm tra ngăn xếp rỗng. Hàm cho kết quả true nếu ngăn xếp rỗng và false trong trường hợp ngược lại.

? Ta có thể truy xuất trực tiếp phần tử tại vị trí bất kỳ trong ngăn xếp được không?

2.2.3. Cài đặt ngăn xếp

Do ngăn xếp là một danh sách đặc biệt nên ta có thể cấu trúc dữ liệu danh sách để

biểu diễn nó. Như vậy, ta có thể khai báo ngăn xếp như sau:

type Stack = List ( hoặc = PList);

Tuy nhiên, để dễ hình dung:

+ Trong cách cài đặt sử dụng mảng ta nên thay trường Count = trường Top + Trong cách cài đặt sử dụng con trỏ, con trỏ quản lý ngăn xếp đặt tên là Top Khi chúng ta đã dùng danh sách để biểu diễn cho ngăn xếp thì ta nên sử dụng các phép toán trên danh sách để cài đặt các phép toán trên ngăn xếp. Sau đây là phần cài đặt ngăn xếp bằng danh sách.

Một phần của tài liệu Bài giảng môn Cấu Trúc Dữ Liệu và Thuật toán doc (Trang 37 - 41)