Linked List — Khi Array không đủ linh hoạt
Ở bài trước, chúng ta đã thấy điểm yếu chí mạng của Array: Chèn và xóa ở giữa mảng cực kỳ tốn kém (O(n)). Nếu bạn đang làm một ứng dụng yêu cầu thay đổi thứ tự dữ liệu liên tục, Array sẽ bóp nghẹt hiệu năng của hệ thống.
Chào mừng bạn đến với cấu trúc dữ liệu khắc phục trực tiếp nhược điểm đó: Linked List (Danh sách liên kết).
📋 Agenda
Thời gian đọc ước tính: ~10 phút
Sau bài này, bạn sẽ:
- ✅ Hiểu được cơ chế hoạt động của Linked List dưới bộ nhớ.
- ✅ Tự tay implement một Singly Linked List hoàn chỉnh từ đầu bằng TypeScript.
- ✅ Giải thích được tại sao thêm/xóa trong Linked List chỉ tốn
O(1). - ✅ Phân biệt được lúc nào nên dùng Array, lúc nào nên dùng Linked List.
Yêu cầu đầu vào:
- 🔹 Có kiến thức cơ bản về Class và Generics trong TypeScript.
❓ Tại sao lại cần Linked List?
Vấn đề (Problem Statement):
Mảng (Array) đòi hỏi một khối lượng bộ nhớ liên tiếp. Khi máy chủ của bạn phân mảnh bộ nhớ (có nhiều vùng trống nhỏ nhưng không có vùng trống nào đủ lớn liền mạch), hệ điều hành sẽ từ chối cấp phát bộ nhớ cho một Array khổng lồ, dẫn đến lỗi "Out of Memory".
Hơn nữa, mỗi lần unshift() hoặc splice() trên Array, hàng ngàn phần tử phải dịch chuyển vị trí rất tốn CPU.
Giải pháp (Solution): Linked List giải quyết bài toán này bằng cách phân tán dữ liệu. Mỗi phần tử (Node) nằm ở bất kỳ đâu trong bộ nhớ. Để chúng không bị lạc mất nhau, Node hiện tại sẽ cầm một "sợi dây" trỏ thẳng đến vị trí của Node tiếp theo. Việc chèn thêm một phần tử mới giờ đây chỉ đơn giản là... cắt đứt sợi dây và nối lại vào người mới. Không ai phải dịch chuyển cả!
📖 Linked List hoạt động thế nào?
Định nghĩa: Linked List là một tập hợp các nút (Nodes). Mỗi Node chứa hai thông tin: Dữ liệu (Value) và Tham chiếu (Pointer/Next) trỏ tới Node tiếp theo trong danh sách.