Bài 60.328 phút đọc
Level 3: Quản lý thư viện
Sau bài này bạn sẽ làm được
- Cài danh sách liên kết cho tài liệu và độc giả
- Dùng bảng băm tra cứu theo mã trong thời gian trung bình O(1)
- Sắp xếp danh sách liên kết bằng merge sort
- Cài hoàn tác thao tác cuối bằng ngăn xếp
Dự án thứ ba nâng độ khó về cấu trúc dữ liệu: danh sách liên kết tự cài, bảng băm tra cứu nhanh, merge sort trên danh sách, và hoàn tác bằng ngăn xếp. Đây là chỗ Phần 5 tới 11 gặp nhau trong một hệ thống thật.
#Mục tiêu
Cấu trúc dữ liệu
typedef enum { GIAO_KHOA, THAM_KHAO, TAP_CHI, LUAN_VAN } LoaiTaiLieu;
typedef struct TaiLieu {
char ma[16], ten[128], tac_gia[64], isbn[20];
int nam, so_luong, con_lai;
LoaiTaiLieu loai;
struct TaiLieu *next; /* danh sach lien ket */
} TaiLieu;
typedef struct {
char ma_the[16], ho_ten[64];
/* danh sach dang muon */
} DocGia;
typedef struct {
char ma_tl[16], ma_the[16];
time_t ngay_muon, han_tra;
} PhieuMuon;| Chức năng | Cấu trúc | Chương |
|---|---|---|
| Lưu tài liệu, độc giả | Danh sách liên kết tự cài | Phần 6, 7 |
| Tra cứu theo mã | Bảng băm | Phần 11 |
| Sắp xếp | Merge sort trên danh sách liên kết | Phần 8, 10 |
| Mượn, trả, phí trễ | time_t và logic nghiệp vụ | Phần 5 |
| Hoàn tác thao tác cuối | Ngăn xếp | Phần 6 |
#Danh sách liên kết
#Bảng băm tra cứu
thuvien.c, danh sách + bảng băm
typedef struct TaiLieu {
char ma[16], ten[64];
int con_lai;
struct TaiLieu *next; /* danh sach lien ket chinh */
struct TaiLieu *hash_next; /* xich trong o bang bam */
} TaiLieu;
#define HASH_CO 16
typedef struct {
TaiLieu *dau; /* dau danh sach */
TaiLieu *bang[HASH_CO]; /* bang bam, moi o mot xich */
int so;
} ThuVien;
static size_t bam(const char *s) {
size_t h = 5381; /* thuat toan djb2 */
for (; *s; ++s) h = h * 33 + (unsigned char)*s;
return h % HASH_CO;
}
static TaiLieu *tra(ThuVien *tv, const char *ma) {
for (TaiLieu *t = tv->bang[bam(ma)]; t; t = t->hash_next)
if (strcmp(t->ma, ma) == 0) return t; /* trung binh O(1) */
return NULL;
}terminal
./thuvien_thu
da them 3 tai lieu tra T002: Cau truc du lieu (con 2) tra T099: khong thay duyet danh sach: T003 T002 T001
#Merge sort danh sách
Chia đôi bằng con trỏ nhanh chậm
Một con trỏ đi hai bước, một con trỏ đi một bước. Khi con trỏ nhanh tới cuối, con trỏ chậm ở giữa. Cắt danh sách ở đó.Đệ quy sắp hai nửa
Gọi merge sort trên nửa đầu và nửa sau.Trộn hai nửa đã sắp
Đi song song hai danh sách, mỗi bước lấy nút nhỏ hơn nối vào kết quả. Chỉ nối con trỏ, không cấp bộ nhớ mới.
#Hoàn tác bằng ngăn xếp
Ghi lại thao tác để hoàn tác
typedef enum { TT_THEM, TT_XOA, TT_SUA } LoaiThaoTac;
typedef struct {
LoaiThaoTac loai;
TaiLieu ban_sao; /* du lieu du de dao nguoc thao tac */
} ThaoTac;
typedef struct {
ThaoTac muc[100]; /* hoac ngan xep dong */
int dinh;
} NganXepHoanTac;
/* Moi thao tac day mot muc vao ngan xep: */
static void ghi_lai(NganXepHoanTac *nx, LoaiThaoTac loai, TaiLieu ban_sao) {
if (nx->dinh < 100) {
nx->muc[nx->dinh].loai = loai;
nx->muc[nx->dinh].ban_sao = ban_sao;
nx->dinh++;
}
}
/* Hoan tac: lay muc tren cung, DAO NGUOC no */
static void hoan_tac(ThuVien *tv, NganXepHoanTac *nx) {
if (nx->dinh == 0) return;
ThaoTac t = nx->muc[--nx->dinh];
switch (t.loai) {
case TT_THEM: /* da them -> gio xoa */ xoa(tv, t.ban_sao.ma); break;
case TT_XOA: /* da xoa -> gio them lai */ them(tv, t.ban_sao); break;
case TT_SUA: /* da sua -> khoi phuc ban cu */ khoi_phuc(tv, t.ban_sao); break;
}
}#Yêu cầu
Tự làm thử
- Danh sách liên kết cho tài liệu và độc giả, tự cài, không dùng mảng.
- Bảng băm tra cứu nhanh theo mã.
- Mượn và trả sách, tính phí trễ hạn, giới hạn số sách mượn.
- Tìm kiếm đa tiêu chí, sắp xếp danh sách liên kết bằng merge sort.
- Báo cáo: sách mượn nhiều nhất, độc giả quá hạn, thống kê theo tháng.
- Lưu trữ bền vững, khôi phục được sau khi thoát.
- Hoàn tác thao tác cuối bằng ngăn xếp.
Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.
Tóm tắt
- Danh sách liên kết để lưu và duyệt, bảng băm để tra cứu nhanh; một tài liệu nằm trong cả hai với hai con trỏ next.
- Bốn thao tác con trỏ: thêm đầu, xoá giữ con trỏ trước, duyệt giữ next trước khi free, không đọc sau khi free.
- Merge sort là thuật toán sắp tự nhiên của danh sách liên kết vì chỉ nối con trỏ.
- Ngăn xếp là cấu trúc đúng cho hoàn tác; mỗi thao tác lưu đủ thông tin để đảo ngược.
- Bản sao hoàn tác phải đủ sâu để không tạo con trỏ treo sau khi giải phóng.