Explore all courses in this category.
Explore all courses in this category.
Nguyễn Đình Cường
0 comment
09 Nov, 2026
Mảng rất tiện, nhưng chèn một phần tử vào giữa thì phải dời cả dãy phía sau. Danh sách liên kết ra đời với cách tổ chức hoàn toàn khác: mỗi phần tử tự biết phần tử kế tiếp nằm ở đâu, giống một chuỗi mắt xích.
Một danh sách liên kết gồm nhiều nút (node). Mỗi nút chứa hai thứ: dữ liệu và một tham chiếu (con trỏ) đến nút tiếp theo. Nút cuối trỏ tới "không có gì" (null hay None). Ta chỉ cần giữ nút đầu tiên, gọi là head, là có thể đi qua cả danh sách.
class Node:
def __init__(self, gia_tri):
self.gia_tri = gia_tri
self.tiep = None
class DanhSach:
def __init__(self):
self.head = None
def them_dau(self, gia_tri):
nut = Node(gia_tri)
nut.tiep = self.head
self.head = nut
def them_cuoi(self, gia_tri):
nut = Node(gia_tri)
if self.head is None:
self.head = nut
return
hien_tai = self.head
while hien_tai.tiep:
hien_tai = hien_tai.tiep
hien_tai.tiep = nut
def in_ra(self):
hien_tai = self.head
while hien_tai:
print(hien_tai.gia_tri, end=" -> ")
hien_tai = hien_tai.tiep
print("None")
ds = DanhSach()
ds.them_dau(2)
ds.them_dau(1)
ds.them_cuoi(3)
ds.in_ra() # 1 -> 2 -> 3 -> NoneĐiểm mạnh của danh sách liên kết nằm ở thao tác chèn và xóa. Giả sử cần chèn nút X vào giữa A và B. Bạn chỉ cần sửa hai tham chiếu: A trỏ tới X, X trỏ tới B. Không có phần tử nào phải dời đi. Với xóa cũng tương tự: cho nút đứng trước bỏ qua nút cần xóa và trỏ thẳng đến nút sau nó.
def xoa(self, gia_tri):
if self.head is None:
return
if self.head.gia_tri == gia_tri:
self.head = self.head.tiep
return
hien_tai = self.head
while hien_tai.tiep and hien_tai.tiep.gia_tri != gia_tri:
hien_tai = hien_tai.tiep
if hien_tai.tiep:
hien_tai.tiep = hien_tai.tiep.tiepHàm trên là một phương thức bạn thêm vào lớp DanhSach. Lưu ý phải xử lý riêng trường hợp xóa nút đầu và trường hợp không tìm thấy.
| Tiêu chí | Mảng | Linked list |
|---|---|---|
| Truy cập phần tử thứ k | Rất nhanh | Phải đi từ đầu, chậm |
| Chèn hoặc xóa ở đầu | Chậm (dời phần tử) | Nhanh |
| Chèn hoặc xóa khi đã có vị trí | Chậm | Nhanh |
| Bộ nhớ | Liền khối, gọn | Mỗi nút tốn thêm chỗ cho con trỏ |
| Hiệu năng bộ nhớ đệm CPU | Thường tốt hơn | Thường kém hơn |
Trên thực tế, với dữ liệu thông thường, mảng thường thắng nhờ tính liền khối thân thiện với CPU. Danh sách liên kết hữu ích khi cần chèn xóa liên tục ở các vị trí đã biết, hoặc khi bạn xây các cấu trúc khác bên trên nó.
Danh sách liên kết rất hay xuất hiện trong bài kiểm tra kỹ thuật: đảo ngược danh sách, tìm nút giữa, phát hiện vòng lặp, gộp hai danh sách đã sắp xếp. Mẹo dùng được cho nhiều bài là kỹ thuật hai con trỏ, một con đi nhanh và một con đi chậm. Trước khi code, hãy vẽ các nút và mũi tên ra giấy, rất nhiều lỗi được tránh nhờ bước này.
head trước khi nối nút cũ vào, bạn đánh mất các nút phía sau. Hãy nối nút mới vào trước rồi mới cập nhật head.hien_tai.tiep.gia_tri khi tiep là None gây lỗi. Kiểm tra trước.Bài tập hay nhất để luyện là đảo ngược danh sách liên kết:
def dao_nguoc(head):
truoc = None
hien_tai = head
while hien_tai:
ke = hien_tai.tiep
hien_tai.tiep = truoc
truoc = hien_tai
hien_tai = ke
return truocBa con trỏ truoc, hien_tai, ke lần lượt đảo chiều từng mũi tên. Hãy vẽ ba nút ra giấy và mô phỏng từng bước để thấy rõ cơ chế.
Danh sách liên kết cho bạn hiểu rõ hơn về tham chiếu và cách dữ liệu nằm trong bộ nhớ. Dù ít khi bạn phải tự viết trong công việc hằng ngày, đây là nền tảng để học cây, đồ thị và hiểu các thư viện hoạt động thế nào bên trong.
Muốn học bài bản và có người hướng dẫn? Hãy xem các khóa học trên codebem.com để đi từ nền tảng đến dự án thực tế.
Nguyễn Đình Cường
0 comment