lOMoARcPSD| 60729183
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ ĐÔNG Á
KHOA CÔNG NGHỆ THÔNG TIN
HỌC PHẦN: CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT
MÃ ĐỀ THI: 3
TÊN ĐỀ TÀI: XÂY DỰNG BÀI TOÁN QUẢN
SÁCH SỬ DỤNG DANH SÁCH LIÊN KẾT ĐƠN LỚP
TÍN CHỈ: CSDL.03.K13.01.LH.C04
Giảng viên hướng dẫn: ThS. Mai Văn Linh
Danh sách sinh viên thực hiện: Nhóm 6
Bắc Ninh – 2025
lOMoARcPSD| 60729183
MỤC LỤC
Lời nói đầu ............................................................................................... 4
Chương 1. TỔNG QUAN VỀ ĐỀ TÀI .................................................. 4
1.1. Giới thiệu đề tài....................................................................................................... 4
CHƯƠNG 2: PHÂN TÍCH ĐỀ TÀI ...................................................... 5
2.1. Dữ liệu lưu trữ ........................................................................................................ 5
2.2. Cấu trúc dữ liệu ...................................................................................................... 5
2.3. Các chức năng chính .............................................................................................. 5
2.4. Thiết kế menu .......................................................................................................... 6
2.4.1. Menu chính (Login Menu) .................................................................................. 6
2.4.2. Menu quản trị viên (Admin Menu) .................................................................... 7
2.4.3. Menu sinh viên (Student Menu) ......................................................................... 7
2.4.4. Thiết kế giao diện hiển thị ................................................................................... 8
CHƯƠNG 3: PHÂN TÍCH CHƯƠNG TRÌNH ................................... 8
3.1. Khai báo thư viện .................................................................................................. 8
3.2. Khởi tạo nút ............................................................................................................ 9
3.3. Nhập dữ liệu .......................................................................................................... 10
3.4. Hiển thị danh sách ................................................................................................ 11
3.5. Thêm vào đầu danh sách ...................................................................................... 12
3.6. Chèn vào cuối danh sách ...................................................................................... 13
3.7. Xóa sách theo mã sách ......................................................................................... 14
3.8. Tìm kiếm theo mã sách ........................................................................................ 14
3.9. Thoát chương trình .............................................................................................. 14
lOMoARcPSD| 60729183
CHƯƠNG 4: MÃ NGUỒN CHƯƠNG TRÌNH ................................. 15
4.1. Mã nguồn ............................................................................................................... 15
Kết luận .................................................................................................. 32
Danh mục sách tham khảo ................................................................... 33
lOMoARcPSD| 60729183
Lời nói đầu
Trong bối cảnh công nghệ thông tin phát triển mạnh mẽ như hiện nay, việc ứng dụng các
cấu trúc dữ liệu và giải thuật vào xây dựng các hệ thống quản lý đã trở thành nhu cầu thiết
yếu. Bài báo cáo này trình bày chi tiết về việc thiết kế và triển khai " Bài toán quản lý sách
sử dụng danh sách liên kết đơn " - một ứng dụng quan trọng trong công tác quản sách và
giao dịch mượn-trả tại các thư viện.
Danh sách liên kết đơn được lựa chọn làm nền tảng cho hệ thống nhờ những ưu điểm vượt
trội trong việc quản dữ liệu động, dễ dàng mở rộng hiệu quả trong các thao tác
thêm/xóa dữ liệu. Đây cũng là cấu trúc dữ liệu cơ bản nhưng đầy sức mạnh, giúp sinh viên
có thể hiểu rõ nguyên lý hoạt động của các cấu trúc dữ liệu phức tạp hơn.
Bài báo cáo được chia thành các phần chính: phân tích yêu cầu hệ thống, thiết kế cấu trúc
dữ liệu, triển khai các giải thuật cơ bản, cùng với đánh giá ưu nhược điểm của phương pháp
tiếp cận. Đặc biệt, chúng tôi tập trung làm rõ cách thức vận hành của từng chức năng quan
trọng như quản lý giao dịch mượn-trả sách, tìm kiếm thông tin, và các thao tác cơ bản trên
danh sách liên kết.
Thông qua báo cáo này, em mong muốn cung cấp một tài liệu tham khảo hữu ích cho những
ai quan tâm đến việc ng dụng cấu trúc dữ liệu vào giải quyết các bài toán thực tế, đồng
thời chia sẻ kinh nghiệm trong quá trình triển khai hệ thống quản lý bằng ngôn ngữ C.
Mặc đã cố gắng hoàn thiện, song o cáo không tránh khỏi những thiếu sót. Em rất
mong nhận được những ý kiến đóng góp quý báu từ quý thầy cô và các bạn để hệ thống có
thể phát triển hoàn thiện hơn trong tương lai.
Chương 1. TỔNG QUAN VỀ ĐỀ TÀI
1.1. Giới thiệu đề tài
Đề tài "Xây dựng bài toán quản lý sách sử dụng danh sách liên kết đơn" là một ứng
dụng thực tế trong lĩnh vực quản lý thư viện và khoa học máy tính. Hệ thống này tập trung
vào việc quản các giao dịch mượn-trả sách trong thư viện bằng cách sử dụng cấu trúc dữ
liệu danh sách liên kết đơn.
Danh ch liên kết đơn (singly linked list) cấu trúc dữ liệu động, mỗi phần tử (node) chứa
dữ liệu con trỏ trỏ tới phần tử tiếp theo. Trong hệ thống này, danh sách liên kết đơn được
lOMoARcPSD| 60729183
sử dụng để lưu trữ thông tin các giao dịch mượn sách, giúp quản hiệu quả với các ưu
điểm:
Dễ dàng thêm/xóa phần tử
Tiết kiệm bộ nhớ khi không cần cấp phát trước
Linh hoạt trong quản lý dữ liệu động
CHƯƠNG 2: PHÂN TÍCH ĐỀ TÀI
2.1. Dữ liệu lưu trữ
Hệ thống quản lý các thông tin sau về giao dịch mượn sách:
Mã sách (bookId): kiểu int - định danh duy nhất cho mỗi cuốn sách
Tên ngành (branchName): kiểu string[100] - chuyên ngành của sách
Thời gian mượn (duration): kiểu int - số ngày mượn
Số thẻ sinh viên (rollNumber): kiểu int - định danh người mượn
Số điện thoại (mobileNumber): kiểu long long - liên hệ người mượn
Ngày mượn: sử dụng macro DATE của C
2.2. Cấu trúc dữ liệu
struct details { char branchName[100]; //
Tên ngành sách int bookId; // Mã
sách
int duration; // Thời gian mượn (ngày)
int rollNumber; // Số thẻ sinh viên long
long int mobileNumber; // Số điện thoại struct
details *next; // Con trỏ tới node tiếp theo
};
2.3. Các chức năng chính
1. Tạo bản ghi mượn sách (createRecord)
lOMoARcPSD| 60729183
Thêm node mới vào cuối danh sách
Kiểm tra trùng mã sách
Tăng biến đếm tổng sách đã mượn (total)
2. Xóa bản ghi trả sách (deleteRecord)
Xóa node theo mã sách
Xử lý 3 trường hợp: xóa đầu danh sách, xóa cuối danh sách, xóa giữa
danh sách
Giảm biến đếm tổng sách đã mượn
3. Hiển thị toàn bộ bản ghi (displayRecords)
Duyệt toàn bộ danh sách từ đầu đến cuối
Hiển thị thông tin định dạng bảng
4. Tìm kiếm bản ghi theo số thẻ (findRecord)
Duyệt danh sách tìm node có rollNumber khớp
Hiển thị tất cả sách sinh viên đã mượn
5. Thay đổi mật khẩu admin (changePassword)
Kiểm tra mật khẩu cũ
Cập nhật mật khẩu mới
2.4. Thiết kế menu
2.4.1. Menu chính (Login Menu)
Hình 1: Login Menu
Chức năng:
Là giao diện đầu tiên khi khởi động chương trình
Phân quyền truy cập cho 2 đối tượng: quản trị viên và sinh viên
Lựa chọn thoát chương trình
lOMoARcPSD| 60729183
2.4.2. Menu quản trị viên (Admin Menu)
Hình 2: Admin Menu
Chức năng chi tiết:
Tạo bản ghi mượn sách: Thêm thông tin mượn sách mới vào hệ thống
Xóa bản ghi trả sách: Xóa bản ghi khi sinh viên trả sách
Hiển thị tất cả bản ghi: Xem toàn bộ giao dịch mượn sách đang có
Đổi mật khẩu: Thay đổi mật khẩu đăng nhập quản trị
Thoát: Quay lại menu chính
2.4.3. Menu sinh viên (Student Menu)
Hình 3:Studen Menu
lOMoARcPSD| 60729183
Chức năng chi tiết:
Xem bản ghi mượn sách: Hiển thị danh sách sách sinh viên đang mượn (tìm
theo số thẻ)
Đăng xuất: Quay lại menu chính
2.4.4. Thiết kế giao diện hiển th
1. Giao diện hiển thị tất cả bản ghi
Hình 4: Giao diện hiển thị tất cả bản ghi
2. Giao diện hiển thị bản ghi sinh viên
Hình 5: Giao diện bản ghi sinh viên
CHƯƠNG 3: PHÂN TÍCH CHƯƠNG TRÌNH
3.1. Khai báo thư viện
Chương trình sử dụng các thư viện C chuẩn sau:
1. stdio.h - Thư viện nhập/xuất chuẩn:
Cung cấp các hàm cơ bản: printf(), scanf()
Hỗ trợ thao tác với file (mặc dù chưa sử dụng trong phiên bản hiện tại)
Macro __DATE__ để lấy ngày hiện tại
2. string.h - Thư viện xử lý chuỗi:
lOMoARcPSD| 60729183
Sử dụng hàm strcmp() để so sánh mật khẩu
Hàm strcpy() để sao chép mật khẩu
Các thao tác xử lý chuỗi khác
3. malloc.h - Thư viện quản lý bộ nhớ động:
Cung cấp hàm malloc() để cấp phát bộ nhớ cho các node mới
Hàm free() để giải phóng bộ nhớ khi xóa node
4. locale.h (được đề xuất thêm) - Thư viện hỗ trợ địa phương hóa:
Hàm setlocale() để thiết lập locale phù hợp hiển thị tiếng Việt
Giúp hiển thị đúng các ký tự có dấu
5. stdlib.h (ngầm định) - Thư viện tiện ích chuẩn:
Hỗ trợ hàm system() để gọi lệnh hệ thống ("cls" để xóa màn hình)
Các hàm quản lý bộ nhớ khác Các thư viện này được chọn vì:
Đủ để triển khai các chức năng cơ bản của hệ thống
Nhẹ và hiệu quả cho bài toán quản lý thư viện
Tương thích tốt trên nhiều nền tảng
Hỗ trợ đầy đủ các thao tác với cấu trúc dữ liệu danh sách liên kết
3.2. Khởi tạo nút
Trong chương trình, việc khởi tạo nút được thực hiện thông qua các bước sau:
1. Cấu trúc dữ liệu nút:
struct details {
char branchName[100]; // Tên ngành sách int
bookId; // Mã sách int duration; //
Thời gian mượn (ngày) int rollNumber; //
Số thẻ sinh viên long long int mobileNumber;
// Số điện thoại struct details *next; // Con trỏ
tới node tiếp theo
};
lOMoARcPSD| 60729183
2. Khởi tạo nút mới:
struct details *new_node = (struct details *)malloc(sizeof(struct details));
3. Quy trình khởi tạo:
Cấp phát bộ nhớ động bằng hàm malloc()
Kiểm tra nếu cấp phát thành công (trong code chính đã bỏ qua bước kiểm tra
này)
Khởi tạo con trỏ next thành NULL khi thêm vào cuối danh sách
3.3. Nhập dữ liệu
Quá trình nhập dữ liệu được thực hiện trong hàm createRecord():
1. Nhập mã sách:
printf("Nhap ma sach: ");
scanf("%d", &bId);
// Kiểm tra trùng mã sách
searchResult = search(bId);
if (searchResult == bId) {
printf("Sach nay khong co san (da duoc muon)\n");
return start;
}
2. Nhập thông tin chi tiết: printf("Nhap nganh: "); scanf("%s", &branch);
printf("Nhap thoi gian muon (ngay): ");
scanf("%d", &dur);
printf("Nhap so the day du: ");
scanf("%d", &rollNo);
lOMoARcPSD| 60729183
printf("Nhap so dien thoai: ");
scanf("%lld", &mobileNo);
3. Gán dữ liệu vào nút:
strcpy(new_node->branchName, branch);
new_node->bookId = bId; new_node-
>duration = dur; new_node->rollNumber =
rollNo;
new_node->mobileNumber = mobileNo;
4. Thêm nút vào danh sách:
if (start == NULL) { // Nếu danh sách rỗng
start = new_node; new_node->next =
NULL; } else { // Nếu danh sách không
rỗng
ptr = start;
while (ptr->next != NULL) { // Duyệt đến cuối danh sách
ptr = ptr->next;
}
ptr->next = new_node; // Thêm nút mới vào cuối
new_node->next = NULL;
}
5. Cập nhật tổng số sách:
total++; // Tăng biến đếm tổng số sách đã mượn printf("\n\t\t*****
Da tao ban ghi! *****\n");
3.4. Hiển thị danh sách
Chức năng hiển thị danh sách được triển khai trong hàm displayRecords():
struct details *displayRecords() { struct
details *ptr;
lOMoARcPSD| 60729183
if (start == NULL) { printf("\t** Khong co ban
ghi de hien thi **\n");
} else { ptr
= start;
printf("\t\t\t
________________________________________________________________________
________________________________________\n"); printf("\t\t\t| MA SACH\t| THOI
GIAN MUON |\t NGAY MUON |\t Ten nganh | So the\t |\tSo dien thoai |\n");
printf("\t\t\t|_______________|____________________|________________|__________
_______|________________|_______________________|\n");
while (ptr != NULL) {
printf("\t\t\t|%d\t | %d ngay\t |\t %s | %s \t| %d\t | %lld\t |\n",
ptr->bookId, ptr->duration, __DATE__, ptr->branchName, ptr->rollNumber, ptr-
>mobileNumber);
printf("\t\t\t|_______________|____________________|________________|__________
_______|________________|_______________________|\n"); ptr
= ptr->next;
} } printf("\n\t\t\t\t\t\t******* Tong so sach da muon: %d *******\n",
total); return start;
}
3.5. Thêm vào đầu danh sách
Hiện tại chương trình chưa triển khai thêm vào đầu danh sách, nhưng có thể bổ sung
như sau:
struct details *insertAtBeginning(struct details *start) { struct details
*new_node = (struct details *)malloc(sizeof(struct details));
lOMoARcPSD| 60729183
// Nhập dữ liệu cho new_node (tương tự createRecord)
if (start == NULL) {
start = new_node;
new_node->next = NULL;
} else { new_node-
>next = start; start =
new_node;
} total++; printf("\n\t\t***** Da them vao dau danh
sach! *****\n"); return start;
}
3.6. Chèn vào cuối danh sách
Chức năng này đã được triển khai trong hàm createRecord() khi thêm bản ghi mới:
// Phần code trong hàm createRecord()
if (start == NULL) { start =
new_node; new_node->next =
NULL;
} else {
ptr = start;
while (ptr->next != NULL) {
ptr = ptr->next;
}
ptr->next = new_node; // Thêm vào cuối danh sách new_node-
>next = NULL;
}
lOMoARcPSD| 60729183
3.7. Xóa sách theo mã sách
Đã triển khai trong hàm deleteRecord():
struct details *deleteRecord() {
struct details *ptr, *prePtr, *postPtr;
int bId; int noBook;
printf("Nhap ma sach can tra: ");
scanf("%d", &bId);
// ... [phần code xử lý xóa]
return start;
}
3.8. Tìm kiếm theo mã sách
int search(int bId) { struct
details *ptr = start; while
(ptr != NULL) { if (ptr-
>bookId == bId) {
return ptr->bookId;
} ptr =
ptr->next; }
return -1; }
3.9. Thoát chương trình
// Trong menu chính case 3:
return 0; // Thoát chương trình
lOMoARcPSD| 60729183
CHƯƠNG 4: MÃ NGUỒN CHƯƠNG TRÌNH
4.1. Mã nguồn
// He thong quan ly thu vien
#include <stdio.h>
#include <string.h>
#include <malloc.h>
struct details // Luu tru thong tin khi tao ban ghi muon sach
{ char branchName[100]; // Ten nganh/chuyen
nganh
int bookId; // ID sach int duration;
// Thoi gian muon (ngay) int rollNumber; //
So the sinh vien long long int mobileNumber; //
So dien thoai struct details *next; // Con tro toi
node tiep theo
}; struct details *start =
NULL;
struct details *createRecord(); // Tao ban ghi muon sach moi
struct details *deleteRecord(); // Xoa ban ghi khi tra sach struct
details *displayRecords(); // Hien thi tat ca ban ghi struct details
*findRecord(); // Tim ban ghi theo so the sinh vien
lOMoARcPSD| 60729183
int search(); // Kiem tra sach da duoc muon chua int
noElementSearch(); // Kiem tra sach chua duoc muon int
noRollSearch(); // Kiem tra sinh vien chua muon sach
nao
struct node
{ char adminPassword[30]; // Luu mat khau
admin
}; struct node *start2 =
NULL;
struct node *changePassword(); // Thay doi mat khau admin
int total = 0; // Theo doi tong so sach da muon (ban dau la 0)
int main() { int choice; // Lua chon trong menu
admin int option; // Lua chon o trang dang nhap
int studentRollNumber; // So the sinh vien char
password[30]; // Mat khau nhap vao struct node
*pass_node; // Con tro toi node chua mat khau
pass_node = (struct node *)malloc(sizeof(struct node)); // Tao node cho mat khau
strcpy(pass_node->adminPassword, "thien123"); // Mat khau mac dinh
printf("\n\t\t\t\t
====================================================\n");
printf("\t\t\t\t CHAO MUNG DEN THU VIEN TRUNG TAM \n");
lOMoARcPSD| 60729183
printf("\t\t\t\t
====================================================\n\n");
do
{
login:
printf("\t\t\t\t\t _______________________________\n"); // Trang dang nhap
printf("\t\t\t\t\t| DANG NHAP |\n");
printf("\t\t\t\t\t|_______________________________|\n");
printf("\t\t\t\t\t| 1- Quan tri vien |\n");
printf("\t\t\t\t\t|_______________________________|\n");
printf("\t\t\t\t\t| 2- Sinh vien |\n");
printf("\t\t\t\t\t|_______________________________|\n");
printf("\t\t\t\t\t| 3- Thoat |\n");
printf("\t\t\t\t\t|_______________________________|\n");
printf("\n\nNhap lua chon: ");
scanf("%d", &option);
switch (option)
{
case
1:
system("cls"); // Xoa man hinh
printf("\nNhap mat khau: "); scanf("%s",
&password);
if (strcmp(password, pass_node->adminPassword) == 0) // Kiem tra mat khau
lOMoARcPSD| 60729183
{
system("cls");
printf("\n\t\t\t\t =================================\n");
printf("\t\t\t\t CHAO MUNG \n");
printf("\t\t\t\t =================================\n");
printf("\t\t\t\t _______________________________________\n"); // Menu
admin
printf("\t\t\t\t| MENU QUAN TRI |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 1-Tao ban ghi muon sach |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 2-Xoa ban ghi tra sach |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 3-Hien thi tat ca ban ghi |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 4-Doi mat khau |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 5-Thoat |\n");
printf("\t\t\t\t|_______________________________________|\n");
do
{
printf("\n\nNhap lua chon: ");
scanf("%d", &choice); printf("\n");
switch (choice)
lOMoARcPSD| 60729183
{
case 1:
start = createRecord();
break;
case 2:
start = deleteRecord();
break;
case 3:
start = displayRecords();
break;
case
4:
start2 = changePassword(pass_node);
if (strcmp(pass_node->adminPassword, "thien123") != 0 ||
strcmp(pass_node->adminPassword, "thien123") == 0)
{
goto login; // Quay lai trang dang nhap sau khi doi mat khau
}
break;
case 5:
system("cls");
break;
default:
printf("\nLua chon khong hop le\n");
}
lOMoARcPSD| 60729183
} while (choice != 5);
} else {
system("cls");
printf("Sai mat khau\n");
}
break;
case
2:
system("cls");
printf("\n\t\t\t\t\t ===============================\n");
printf("\t\t\t\t\t CHAO MUNG \n");
printf("\t\t\t\t\t ===============================\n\n");
printf("\t\t\t\t\t __________________________________\n"); // Menu sinh vien
printf("\t\t\t\t\t| 1- Xem ban ghi muon sach |\n");
printf("\t\t\t\t\t|__________________________________|\n");
printf("\t\t\t\t\t| 2- Dang xuat |\n");
printf("\t\t\t\t\t|__________________________________|\n");
do
{
printf("\n\nNhap lua chon: ");
scanf("%d", &studentRollNumber);
switch (studentRollNumber)
{ case
1:

Preview text:

lOMoAR cPSD| 60729183
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ ĐÔNG Á
KHOA CÔNG NGHỆ THÔNG TIN
HỌC PHẦN: CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT MÃ ĐỀ THI: 3
TÊN ĐỀ TÀI: XÂY DỰNG BÀI TOÁN QUẢN LÍ
SÁCH SỬ DỤNG DANH SÁCH LIÊN KẾT ĐƠN LỚP
TÍN CHỈ: CSDL.03.K13.01.LH.C04
Giảng viên hướng dẫn: ThS. Mai Văn Linh
Danh sách sinh viên thực hiện: Nhóm 6 Bắc Ninh – 2025 lOMoAR cPSD| 60729183 MỤC LỤC
Lời nói đầu ............................................................................................... 4
Chương 1. TỔNG QUAN VỀ ĐỀ TÀI .................................................. 4

1.1. Giới thiệu đề tài....................................................................................................... 4
CHƯƠNG 2: PHÂN TÍCH ĐỀ TÀI ...................................................... 5
2.1. Dữ liệu lưu trữ ........................................................................................................ 5
2.2. Cấu trúc dữ liệu ...................................................................................................... 5
2.3. Các chức năng chính .............................................................................................. 5
2.4. Thiết kế menu .......................................................................................................... 6
2.4.1. Menu chính (Login Menu) .................................................................................. 6
2.4.2. Menu quản trị viên (Admin Menu) .................................................................... 7
2.4.3. Menu sinh viên (Student Menu) ......................................................................... 7
2.4.4. Thiết kế giao diện hiển thị ................................................................................... 8
CHƯƠNG 3: PHÂN TÍCH CHƯƠNG TRÌNH ................................... 8
3.1. Khai báo thư viện .................................................................................................. 8
3.2. Khởi tạo nút ............................................................................................................ 9
3.3. Nhập dữ liệu .......................................................................................................... 10
3.4. Hiển thị danh sách ................................................................................................ 11
3.5. Thêm vào đầu danh sách ...................................................................................... 12
3.6. Chèn vào cuối danh sách ...................................................................................... 13
3.7. Xóa sách theo mã sách ......................................................................................... 14
3.8. Tìm kiếm theo mã sách ........................................................................................ 14
3.9. Thoát chương trình .............................................................................................. 14 lOMoAR cPSD| 60729183
CHƯƠNG 4: MÃ NGUỒN CHƯƠNG TRÌNH ................................. 15
4.1. Mã nguồn ............................................................................................................... 15
Kết luận .................................................................................................. 32
Danh mục sách tham khảo ................................................................... 33
lOMoAR cPSD| 60729183 Lời nói đầu
Trong bối cảnh công nghệ thông tin phát triển mạnh mẽ như hiện nay, việc ứng dụng các
cấu trúc dữ liệu và giải thuật vào xây dựng các hệ thống quản lý đã trở thành nhu cầu thiết
yếu. Bài báo cáo này trình bày chi tiết về việc thiết kế và triển khai " Bài toán quản lý sách
sử dụng danh sách liên kết đơn " - một ứng dụng quan trọng trong công tác quản lý sách và
giao dịch mượn-trả tại các thư viện.
Danh sách liên kết đơn được lựa chọn làm nền tảng cho hệ thống nhờ những ưu điểm vượt
trội trong việc quản lý dữ liệu động, dễ dàng mở rộng và hiệu quả trong các thao tác
thêm/xóa dữ liệu. Đây cũng là cấu trúc dữ liệu cơ bản nhưng đầy sức mạnh, giúp sinh viên
có thể hiểu rõ nguyên lý hoạt động của các cấu trúc dữ liệu phức tạp hơn.
Bài báo cáo được chia thành các phần chính: phân tích yêu cầu hệ thống, thiết kế cấu trúc
dữ liệu, triển khai các giải thuật cơ bản, cùng với đánh giá ưu nhược điểm của phương pháp
tiếp cận. Đặc biệt, chúng tôi tập trung làm rõ cách thức vận hành của từng chức năng quan
trọng như quản lý giao dịch mượn-trả sách, tìm kiếm thông tin, và các thao tác cơ bản trên danh sách liên kết.
Thông qua báo cáo này, em mong muốn cung cấp một tài liệu tham khảo hữu ích cho những
ai quan tâm đến việc ứng dụng cấu trúc dữ liệu vào giải quyết các bài toán thực tế, đồng
thời chia sẻ kinh nghiệm trong quá trình triển khai hệ thống quản lý bằng ngôn ngữ C.
Mặc dù đã cố gắng hoàn thiện, song báo cáo không tránh khỏi những thiếu sót. Em rất
mong nhận được những ý kiến đóng góp quý báu từ quý thầy cô và các bạn để hệ thống có
thể phát triển hoàn thiện hơn trong tương lai.
Chương 1. TỔNG QUAN VỀ ĐỀ TÀI
1.1. Giới thiệu đề tài
Đề tài "Xây dựng bài toán quản lý sách sử dụng danh sách liên kết đơn" là một ứng
dụng thực tế trong lĩnh vực quản lý thư viện và khoa học máy tính. Hệ thống này tập trung
vào việc quản lý các giao dịch mượn-trả sách trong thư viện bằng cách sử dụng cấu trúc dữ
liệu danh sách liên kết đơn.
Danh sách liên kết đơn (singly linked list) là cấu trúc dữ liệu động, mỗi phần tử (node) chứa
dữ liệu và con trỏ trỏ tới phần tử tiếp theo. Trong hệ thống này, danh sách liên kết đơn được lOMoAR cPSD| 60729183
sử dụng để lưu trữ thông tin các giao dịch mượn sách, giúp quản lý hiệu quả với các ưu điểm: •
Dễ dàng thêm/xóa phần tử •
Tiết kiệm bộ nhớ khi không cần cấp phát trước •
Linh hoạt trong quản lý dữ liệu động
CHƯƠNG 2: PHÂN TÍCH ĐỀ TÀI
2.1. Dữ liệu lưu trữ
Hệ thống quản lý các thông tin sau về giao dịch mượn sách: •
Mã sách (bookId): kiểu int - định danh duy nhất cho mỗi cuốn sách •
Tên ngành (branchName): kiểu string[100] - chuyên ngành của sách •
Thời gian mượn (duration): kiểu int - số ngày mượn •
Số thẻ sinh viên (rollNumber): kiểu int - định danh người mượn •
Số điện thoại (mobileNumber): kiểu long long - liên hệ người mượn •
Ngày mượn: sử dụng macro DATE của C
2.2. Cấu trúc dữ liệu
struct details { char branchName[100]; //
Tên ngành sách int bookId; // Mã sách
int duration; // Thời gian mượn (ngày)
int rollNumber; // Số thẻ sinh viên long
long int mobileNumber; // Số điện thoại struct
details *next; // Con trỏ tới node tiếp theo };
2.3. Các chức năng chính
1. Tạo bản ghi mượn sách (createRecord) lOMoAR cPSD| 60729183
• Thêm node mới vào cuối danh sách
• Kiểm tra trùng mã sách
• Tăng biến đếm tổng sách đã mượn (total)
2. Xóa bản ghi trả sách (deleteRecord) • Xóa node theo mã sách
• Xử lý 3 trường hợp: xóa đầu danh sách, xóa cuối danh sách, xóa giữa danh sách
• Giảm biến đếm tổng sách đã mượn
3. Hiển thị toàn bộ bản ghi (displayRecords)
• Duyệt toàn bộ danh sách từ đầu đến cuối
• Hiển thị thông tin định dạng bảng
4. Tìm kiếm bản ghi theo số thẻ (findRecord)
• Duyệt danh sách tìm node có rollNumber khớp
• Hiển thị tất cả sách sinh viên đã mượn
5. Thay đổi mật khẩu admin (changePassword)
• Kiểm tra mật khẩu cũ
• Cập nhật mật khẩu mới
2.4. Thiết kế menu
2.4.1. Menu chính (Login Menu)
Hình 1: Login Menu Chức năng:
• Là giao diện đầu tiên khi khởi động chương trình
• Phân quyền truy cập cho 2 đối tượng: quản trị viên và sinh viên
• Lựa chọn thoát chương trình lOMoAR cPSD| 60729183
2.4.2. Menu quản trị viên (Admin Menu) Hình 2: Admin Menu
Chức năng chi tiết:
Tạo bản ghi mượn sách: Thêm thông tin mượn sách mới vào hệ thống
Xóa bản ghi trả sách: Xóa bản ghi khi sinh viên trả sách
Hiển thị tất cả bản ghi: Xem toàn bộ giao dịch mượn sách đang có
Đổi mật khẩu: Thay đổi mật khẩu đăng nhập quản trị
Thoát: Quay lại menu chính
2.4.3. Menu sinh viên (Student Menu) Hình 3:Studen Menu lOMoAR cPSD| 60729183
Chức năng chi tiết:
Xem bản ghi mượn sách: Hiển thị danh sách sách sinh viên đang mượn (tìm theo số thẻ)
Đăng xuất: Quay lại menu chính
2.4.4. Thiết kế giao diện hiển thị
1. Giao diện hiển thị tất cả bản ghi
Hình 4: Giao diện hiển thị tất cả bản ghi
2. Giao diện hiển thị bản ghi sinh viên
Hình 5: Giao diện bản ghi sinh viên
CHƯƠNG 3: PHÂN TÍCH CHƯƠNG TRÌNH
3.1. Khai báo thư viện
Chương trình sử dụng các thư viện C chuẩn sau:
1. stdio.h - Thư viện nhập/xuất chuẩn:
• Cung cấp các hàm cơ bản: printf(), scanf()
• Hỗ trợ thao tác với file (mặc dù chưa sử dụng trong phiên bản hiện tại)
• Macro __DATE__ để lấy ngày hiện tại
2. string.h - Thư viện xử lý chuỗi: lOMoAR cPSD| 60729183
• Sử dụng hàm strcmp() để so sánh mật khẩu
• Hàm strcpy() để sao chép mật khẩu
• Các thao tác xử lý chuỗi khác
3. malloc.h - Thư viện quản lý bộ nhớ động:
• Cung cấp hàm malloc() để cấp phát bộ nhớ cho các node mới
• Hàm free() để giải phóng bộ nhớ khi xóa node
4. locale.h (được đề xuất thêm) - Thư viện hỗ trợ địa phương hóa:
• Hàm setlocale() để thiết lập locale phù hợp hiển thị tiếng Việt
• Giúp hiển thị đúng các ký tự có dấu
5. stdlib.h (ngầm định) - Thư viện tiện ích chuẩn:
• Hỗ trợ hàm system() để gọi lệnh hệ thống ("cls" để xóa màn hình)
• Các hàm quản lý bộ nhớ khác Các thư viện này được chọn vì:
• Đủ để triển khai các chức năng cơ bản của hệ thống
• Nhẹ và hiệu quả cho bài toán quản lý thư viện
• Tương thích tốt trên nhiều nền tảng
• Hỗ trợ đầy đủ các thao tác với cấu trúc dữ liệu danh sách liên kết 3.2. Khởi tạo nút
Trong chương trình, việc khởi tạo nút được thực hiện thông qua các bước sau:
1. Cấu trúc dữ liệu nút: struct details {
char branchName[100]; // Tên ngành sách int
bookId; // Mã sách int duration; //
Thời gian mượn (ngày) int rollNumber; //
Số thẻ sinh viên long long int mobileNumber;
// Số điện thoại struct details *next; // Con trỏ tới node tiếp theo }; lOMoAR cPSD| 60729183
2. Khởi tạo nút mới:
struct details *new_node = (struct details *)malloc(sizeof(struct details));
3. Quy trình khởi tạo:
• Cấp phát bộ nhớ động bằng hàm malloc()
• Kiểm tra nếu cấp phát thành công (trong code chính đã bỏ qua bước kiểm tra này)
• Khởi tạo con trỏ next thành NULL khi thêm vào cuối danh sách 3.3. Nhập dữ liệu
Quá trình nhập dữ liệu được thực hiện trong hàm createRecord(): 1. Nhập mã sách: printf("Nhap ma sach: "); scanf("%d", &bId);
// Kiểm tra trùng mã sách searchResult = search(bId); if (searchResult == bId) {
printf("Sach nay khong co san (da duoc muon)\n"); return start; }
2. Nhập thông tin chi tiết: printf("Nhap nganh: "); scanf("%s", &branch);
printf("Nhap thoi gian muon (ngay): "); scanf("%d", &dur);
printf("Nhap so the day du: "); scanf("%d", &rollNo); lOMoAR cPSD| 60729183
printf("Nhap so dien thoai: "); scanf("%lld", &mobileNo);
3. Gán dữ liệu vào nút:
strcpy(new_node->branchName, branch);
new_node->bookId = bId; new_node-
>duration = dur; new_node->rollNumber = rollNo;
new_node->mobileNumber = mobileNo;
4. Thêm nút vào danh sách:
if (start == NULL) { // Nếu danh sách rỗng
start = new_node; new_node->next =
NULL; } else { // Nếu danh sách không rỗng ptr = start;
while (ptr->next != NULL) { // Duyệt đến cuối danh sách ptr = ptr->next; }
ptr->next = new_node; // Thêm nút mới vào cuối new_node->next = NULL; }
5. Cập nhật tổng số sách:
total++; // Tăng biến đếm tổng số sách đã mượn printf("\n\t\t***** Da tao ban ghi! *****\n");
3.4. Hiển thị danh sách
Chức năng hiển thị danh sách được triển khai trong hàm displayRecords():
struct details *displayRecords() { struct details *ptr; lOMoAR cPSD| 60729183
if (start == NULL) { printf("\t** Khong co ban ghi de hien thi **\n"); } else { ptr = start; printf("\t\t\t
________________________________________________________________________
________________________________________\n"); printf("\t\t\t| MA SACH\t| THOI
GIAN MUON |\t NGAY MUON |\t Ten nganh | So the\t |\tSo dien thoai |\n");
printf("\t\t\t|_______________|____________________|________________|__________
_______|________________|_______________________|\n"); while (ptr != NULL) {
printf("\t\t\t|%d\t | %d ngay\t |\t %s | %s \t| %d\t | %lld\t |\n",
ptr->bookId, ptr->duration, __DATE__, ptr->branchName, ptr->rollNumber, ptr- >mobileNumber);
printf("\t\t\t|_______________|____________________|________________|__________
_______|________________|_______________________|\n"); ptr = ptr->next;
} } printf("\n\t\t\t\t\t\t******* Tong so sach da muon: %d *******\n", total); return start; }
3.5. Thêm vào đầu danh sách
Hiện tại chương trình chưa triển khai thêm vào đầu danh sách, nhưng có thể bổ sung như sau:
struct details *insertAtBeginning(struct details *start) { struct details
*new_node = (struct details *)malloc(sizeof(struct details)); lOMoAR cPSD| 60729183
// Nhập dữ liệu cho new_node (tương tự createRecord) if (start == NULL) { start = new_node; new_node->next = NULL; } else { new_node- >next = start; start = new_node;
} total++; printf("\n\t\t***** Da them vao dau danh
sach! *****\n"); return start; }
3.6. Chèn vào cuối danh sách
Chức năng này đã được triển khai trong hàm createRecord() khi thêm bản ghi mới:
// Phần code trong hàm createRecord() if (start == NULL) { start = new_node; new_node->next = NULL; } else { ptr = start;
while (ptr->next != NULL) { ptr = ptr->next; }
ptr->next = new_node; // Thêm vào cuối danh sách new_node- >next = NULL; } lOMoAR cPSD| 60729183
3.7. Xóa sách theo mã sách
Đã triển khai trong hàm deleteRecord():
struct details *deleteRecord() {
struct details *ptr, *prePtr, *postPtr; int bId; int noBook;
printf("Nhap ma sach can tra: "); scanf("%d", &bId);
// ... [phần code xử lý xóa] return start; }
3.8. Tìm kiếm theo mã sách
int search(int bId) { struct details *ptr = start; while (ptr != NULL) { if (ptr- >bookId == bId) { return ptr->bookId; } ptr = ptr->next; } return -1; }
3.9. Thoát chương trình // Trong menu chính case 3:
return 0; // Thoát chương trình lOMoAR cPSD| 60729183
CHƯƠNG 4: MÃ NGUỒN CHƯƠNG TRÌNH 4.1. Mã nguồn
// He thong quan ly thu vien #include #include #include
struct details // Luu tru thong tin khi tao ban ghi muon sach
{ char branchName[100]; // Ten nganh/chuyen nganh
int bookId; // ID sach int duration;
// Thoi gian muon (ngay) int rollNumber; //
So the sinh vien long long int mobileNumber; //
So dien thoai struct details *next; // Con tro toi node tiep theo
}; struct details *start = NULL;
struct details *createRecord(); // Tao ban ghi muon sach moi
struct details *deleteRecord(); // Xoa ban ghi khi tra sach struct
details *displayRecords(); // Hien thi tat ca ban ghi struct details
*findRecord(); // Tim ban ghi theo so the sinh vien lOMoAR cPSD| 60729183
int search(); // Kiem tra sach da duoc muon chua int
noElementSearch(); // Kiem tra sach chua duoc muon int
noRollSearch(); // Kiem tra sinh vien chua muon sach nao struct node
{ char adminPassword[30]; // Luu mat khau admin
}; struct node *start2 = NULL;
struct node *changePassword(); // Thay doi mat khau admin
int total = 0; // Theo doi tong so sach da muon (ban dau la 0)
int main() { int choice; // Lua chon trong menu
admin int option; // Lua chon o trang dang nhap
int studentRollNumber; // So the sinh vien char
password[30]; // Mat khau nhap vao struct node
*pass_node; // Con tro toi node chua mat khau
pass_node = (struct node *)malloc(sizeof(struct node)); // Tao node cho mat khau
strcpy(pass_node->adminPassword, "thien123"); // Mat khau mac dinh printf("\n\t\t\t\t
====================================================\n");
printf("\t\t\t\t CHAO MUNG DEN THU VIEN TRUNG TAM \n"); lOMoAR cPSD| 60729183 printf("\t\t\t\t
====================================================\n\n"); do { login:
printf("\t\t\t\t\t _______________________________\n"); // Trang dang nhap
printf("\t\t\t\t\t| DANG NHAP |\n");
printf("\t\t\t\t\t|_______________________________|\n");
printf("\t\t\t\t\t| 1- Quan tri vien |\n");
printf("\t\t\t\t\t|_______________________________|\n");
printf("\t\t\t\t\t| 2- Sinh vien |\n");
printf("\t\t\t\t\t|_______________________________|\n");
printf("\t\t\t\t\t| 3- Thoat |\n");
printf("\t\t\t\t\t|_______________________________|\n");
printf("\n\nNhap lua chon: "); scanf("%d", &option); switch (option) { case 1:
system("cls"); // Xoa man hinh
printf("\nNhap mat khau: "); scanf("%s", &password);
if (strcmp(password, pass_node->adminPassword) == 0) // Kiem tra mat khau lOMoAR cPSD| 60729183 { system("cls");
printf("\n\t\t\t\t =================================\n");
printf("\t\t\t\t CHAO MUNG \n");
printf("\t\t\t\t =================================\n");
printf("\t\t\t\t _______________________________________\n"); // Menu admin
printf("\t\t\t\t| MENU QUAN TRI |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 1-Tao ban ghi muon sach |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 2-Xoa ban ghi tra sach |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 3-Hien thi tat ca ban ghi |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 4-Doi mat khau |\n");
printf("\t\t\t\t|_______________________________________|\n");
printf("\t\t\t\t| 5-Thoat |\n");
printf("\t\t\t\t|_______________________________________|\n"); do {
printf("\n\nNhap lua chon: ");
scanf("%d", &choice); printf("\n"); switch (choice) lOMoAR cPSD| 60729183 { case 1: start = createRecord(); break; case 2: start = deleteRecord(); break; case 3: start = displayRecords(); break; case 4:
start2 = changePassword(pass_node);
if (strcmp(pass_node->adminPassword, "thien123") != 0 ||
strcmp(pass_node->adminPassword, "thien123") == 0) {
goto login; // Quay lai trang dang nhap sau khi doi mat khau } break; case 5: system("cls"); break; default:
printf("\nLua chon khong hop le\n"); } lOMoAR cPSD| 60729183 } while (choice != 5); } else { system("cls"); printf("Sai mat khau\n"); } break; case 2: system("cls");
printf("\n\t\t\t\t\t ===============================\n");
printf("\t\t\t\t\t CHAO MUNG \n");
printf("\t\t\t\t\t ===============================\n\n");
printf("\t\t\t\t\t __________________________________\n"); // Menu sinh vien
printf("\t\t\t\t\t| 1- Xem ban ghi muon sach |\n");
printf("\t\t\t\t\t|__________________________________|\n");
printf("\t\t\t\t\t| 2- Dang xuat |\n");
printf("\t\t\t\t\t|__________________________________|\n"); do {
printf("\n\nNhap lua chon: ");
scanf("%d", &studentRollNumber); switch (studentRollNumber) { case 1: