Danh sách liên kết đôi & vòng
Linked list đơn chỉ đi một chiều. Bài này thêm hai biến thể: đôi (doubly) — mỗi nút biết cả nút trước, đi được hai chiều; và vòng (circular) — nút cuối nối lại về đầu. Mỗi loại giải một nhu cầu khác nhau.
1. Danh sách liên kết ĐÔI (doubly)
Mỗi nút có hai con trỏ: next (nút sau) và prev (nút trước). Nhờ vậy đi được cả hai chiều.
┌────┬───┬───┐ ┌────┬───┬───┐ ┌────┬───┬────┐
None◀───┼─● │10 │ ●─┼──▶┼─● │20 │ ●─┼──▶┼─● │30 │None│
│prev│val│nxt│◀──┼prev│val│nxt│◀──┼prev│val│nxt │
└────┴───┴───┘ └────┴───┴───┘ └────┴───┴────┘
Được: đi lùi dễ, xóa một nút khi đã có con trỏ tới nó là O(1) (vì biết cả nút trước).
Trả giá: mỗi nút tốn thêm con tr ỏ prev; code phải cập nhật hai chiều khi sửa.
2. Chạy debug: đi NGƯỢC nhờ prev
Điều linked list đơn không làm được: đi từ cuối về đầu. Bước qua:
3. Danh sách liên kết VÒNG (circular)
Nút cuối thay vì trỏ None thì trỏ ngược về đầu → tạo thành một vòng tròn không điểm kết.
┌──▶┌────┬───┐ ┌────┬───┐ ┌────┬───┐──┐
│ │ 10 │ ●─┼──▶│ 20 │ ●─┼──▶│ 30 │ ●─┼─ │
│ └────┴───┘ └────┴───┘ └────┴───┘ │
└──────────────────────────────────────────┘
Ứng dụng: mọi thứ xoay vòng — lượt chơi trong game nhiều người, vòng phát nhạc lặp lại, lập lịch round-robin của CPU, bộ đệm vòng (circular buffer).
Vì không có None kết thúc, duyệt danh sách vòng phải có điều kiện dừng riêng (vd quay lại
đúng nút đầu), nếu không sẽ chạy mãi mãi.
4. Ba loại — chọn loại nào?
| Loại | Đặc điểm | Dùng khi |
|---|---|---|
| Đơn | chỉ next, đi một chiều | đơn giản, tiết kiệm bộ nhớ; stack, queue cơ bản |
| Đôi | next + prev, hai chiều | cần đi lùi / xóa nút O(1); deque, LRU cache, undo/redo |
| Vòng | cuối nối về đầu | dữ liệu xoay vòng; round-robin, circular buffer |
5. Mẫu nhận diện
- Cần đi lùi hoặc xóa nhanh khi đã trỏ tới nút → danh sách đôi.
- Dữ liệu lặp vòng (lượt, vòng phát, lịch xoay) → danh sách vòng.
- Không cần hai thứ trên → danh sách đơn cho gọn nhẹ.
6. 🎮 Trò chơi: Đôi hay vòng?
7. Quiz kiểm tra nhanh
8. Hoàn thành
…☑️ Tiếp theo: 2.2.3 — Thao tác: chèn, xóa, đảo ngược.