Phân tích thuật toán Dữ liệu đầu vào và đầu ra Đầu vào: Thông tin sinh viên từ bàn phím mã, tên, tuổi, điểm trung bình.Đầu ra: Danh sách được sắp xếp, hiển thị hoặc các thông tin tìm kiế
Trang 1TRƯỜNG ĐẠI HỌC GIAO THÔNG VÂN TẢI
KHOA ĐIỆN-ĐIỆN TỬ
-o0o -BÀI TẬP LỚN MÔN HỌC CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT
Giảng viên hướng dẫn: ThS Phạm Xuân Tích
Sinh viên thực hiện: Trần Anh Đức - Lớp KTĐK&TĐH1-K64
Đề tài số: 21
Hà Nội, tháng 11 năm 2024
Trang 2Phần A Bài toán quản lý
Sinh viên làm bài tập về quản lý (đề tài sinh viên tự đề xuất) Sinh viên
sử dụng (không xây dựng chỉ sử dụng cấu trúc vector hoặc list có sẵn trong STL làm bài toán quản lý theo các yêu cầu sau:
+ Tên do sinh viên tự đề xuất (ví dụ quản lý sinh viên, quản lý điểm, quản lý
giảng viên, quản lý hàng hóa, quản lý thời khóa biểu, quản lý ô tô …) mỗi sinhviên một đề tài
+ Xây dựng ít nhất 03 lớp gồm:
- Xây dựng lớp đối tượng quản lý có ít nhất 04 trường dữ liệu (ví dụ sinh
viên gồm mã, tên, tuổi, điểm) với ít nhất 03 gồm toán tử >> và << và 01 toán tử so
sánh < (theo 1 trường nào đó ví dụ điểm)
- Xây dựng lớp danh sách đối tượng quản lý (dùng cấu trúc vector nếu số
cuối cùng mã sinh viên là số chẳn, dòng cấu trúc list nếu số cuối cùng mã sinh viên
là số lẻ) cho phép nhập, xuất danh sách, sắp xếp danh sách (dùng hàm sort có sẵnđối với vector và phương thức sort có sẵn đối với list) và ít nhất 03 thao tác ví dụtìm max, min, tìm kiếm, xóa, thêm …
- Xây dựng lớp app để quản lý có menu và thực hiện các thao tác ở lớp danh
sách
- Viết hàm main chạy chương trình
Phân tích bài toán
1 Yêu cầu đề tài (tên)
Quản lý sinh viên
Quản lý điểm, quản lý giảng viên, quản lý hàng hóa, thời khóa biểu, ô tô
2 Yêu cầu về các lớp
Lớp đối tượng quản lý (sinhvien)
Mục đích: Quản lý thông tin của một đối tượng đơn lẻ, ở đây là "Sinh viên".
Dữ liệu yêu cầu:
Lớp này chứa ít nhất 4 trường dữ liệu, đã được triển khai như sau:
Trang 3masv (Mã sinh viên): Chuỗi ký tự đại diện cho mã sinh viên.
ten (Tên sinh viên): Chuỗi ký tự chứa họ tên
tuoi (Tuổi sinh viên): Giá trị nguyên
diemtb (Điểm trung bình): Giá trị số thực
Toán tử cần cài đặt:
>> (Nhập từ bàn phím): Cho phép nhập thông tin đối tượng từ người dùng
<< (Xuất ra màn hình): Cho phép hiển thị đối tượng
< (So sánh nhỏ hơn): So sánh hai đối tượng theo điểm trung bình để sắp xếp danh sách
Lớp danh sách đối tượng quản lý (danhsachsinhvien)
Mục đích: Quản lý danh sách các đối tượng (danh sách sinh viên)
Tính năng:
Thêm đối tượng: Hàm them_sinhvien() thêm đối tượng vào danh sách
Xóa đối tượng: Hàm xoa_sinhvien() xóa đối tượng theo mã
Hiển thị danh sách: Hàm hien_thi_danhsach() xuất toàn bộ danh sách ra mànhình
Sắp xếp: Hàm sapxep_danhsach() sắp xếp danh sách theo điểm trung bình bằng:
std::sort với std::vector
list::sort nếu chuyển sang std::list
Tìm điểm cao nhất: Hàm tim_max_diem() xác định sinh viên có điểm cao nhất
Tìm kiếm theo mã: Hàm timkiem_theo_ma() tìm đối tượng theo mã sinh viên
Lớp ứng dụng (app)
Mục đích: Tạo menu quản lý, cho phép người dùng thao tác với danh sách thông qua các chức năng:
Thêm sinh viên
Xóa sinh viên theo mã
Hiển thị danh sách sinh viên
Sắp xếp danh sách
Tìm sinh viên có điểm cao nhất
Tìm sinh viên theo mã
Thoát chương trình
3 Hàm main
Chạy ứng dụng bằng cách tạo đối tượng app và gọi hàm menu()
Trang 4Cho phép người dùng nhập lựa chọn và thực hiện các thao tác tương ứng.
4 Phân tích thuật toán
Dữ liệu đầu vào và đầu ra
Đầu vào: Thông tin sinh viên từ bàn phím (mã, tên, tuổi, điểm trung bình).Đầu ra: Danh sách được sắp xếp, hiển thị hoặc các thông tin tìm kiếm
Cấu trúc dữ liệu
Sử dụng std::vector: Mặc định trong mã, dễ dàng quản lý danh sách với các thao tác như thêm, xóa, sắp xếp
Nếu cần tích hợp std::list, thay thế vector bằng list và chỉnh sửa:
sort(ds.begin(), ds.end()) → ds.sort()
Các thao tác chính
Thêm sinh viên:
Thêm đối tượng vào cuối danh sách với vector::push_back()
Xóa sinh viên:
Dùng remove_if và vector::erase() để xóa các đối tượng có mã trùng với mã được nhập
Dùng std::find_if() để tìm đối tượng theo mã sinh viên
5 Những cải tiến cần thiết
Kiểm tra mã sinh viên để chọn vector hoặc list:
Trang 5sinhvien(string ma, string ten, int tuoi, float diem)
: masv(ma), ten(ten), tuoi(tuoi), diemtb(diem) {}
// toan tu >>
friend istream& operator>>(istream& is, sinhvien& sv) { cout << "nhap ma sinh vien: ";
is >> sv.masv;
Trang 6is.ignore(numeric_limits<streamsize>::max(), '\n'); // clear buffer cout << "nhap ten sinh vien: ";
getline(is, sv.ten);
cout << "nhap tuoi: ";
while (!(is >> sv.tuoi)) { // validate integer input
cout << "tuoi khong hop le nhap lai: ";
is.clear();
is.ignore(numeric_limits<streamsize>::max(), '\n');
}
cout << "nhap diem trung binh: ";
while (!(is >> sv.diemtb)) { // validate float input
cout << "diem khong hop le nhap lai: ";
friend ostream& operator<<(ostream& os, const sinhvien& sv) {
os << "ma sv: " << sv.masv << " | ten: " << sv.ten
Trang 7<< " | tuoi: " << sv.tuoi << " | diem tb: " << sv.diemtb; return os;
}
// toan tu <
bool operator<(const sinhvien& other) const {
return diemtb < other.diemtb;
}
// getter
string get_masv() const { return masv; }
string get_ten() const { return ten; }
float get_diemtb() const { return diemtb; }
Trang 8// them sinh vien
void them_sinhvien(const sinhvien& sv) {
ds.push_back(sv);
}
// xoa sinh vien theo ma
void xoa_sinhvien(const string& masv) {
auto it = remove_if(ds.begin(), ds.end(), [&](const sinhvien& sv) { return sv.get_masv() == masv;
// hien thi danh sach
void hien_thi_danhsach() const {
if (ds.empty()) {
Trang 9cout << "danh sach trong!" << endl;
// tim sinh vien co diem cao nhat
void tim_max_diem() const {
if (ds.empty()) {
Trang 10cout << "danh sach trong, khong co sinh vien nao!" << endl; return;
}
auto max_sv = *max_element(ds.begin(), ds.end());
cout << "sinh vien co diem cao nhat: " << endl;
cout << max_sv << endl;
}
// tim kiem sinh vien theo ma
void timkiem_theo_ma(const string& masv) const {
auto it = find_if(ds.begin(), ds.end(), [&](const sinhvien& sv) { return sv.get_masv() == masv;
Trang 11// class app de quan ly
cout << "1 them sinh vien\n";
cout << "2 xoa sinh vien\n";
cout << "3 hien thi danh sach sinh vien\n"; cout << "4 sap xep danh sach theo diem\n"; cout << "5 tim sinh vien co diem cao nhat\n"; cout << "6 tim kiem sinh vien theo ma\n"; cout << "0 thoat\n";
cout << "lua chon: ";
int choice;
cin >> choice;
switch (choice) {
Trang 14app.menu();
return 0;
}
3 Phân tích thời gian chạy của từng phương thức có trong các lớp
them_sinhvien: O(1), do thêm vào cuối danh sách.
xoa_sinhvien: O(n), duyệt toàn bộ danh sách để tìm sinh viên cần xóa.
hien_thi_danhsach: O(n), duyệt qua toàn bộ danh sách để in.
sap_xep_danhsach: O(nlogn), sử dụng thuật toán sắp xếp.
tim_max_diem: O(n), duyệt toàn bộ danh sách để tìm giá trị
timkiem_theo_ma: O(n), duyệt qua danh sách đến khi tìm thấy.
4 Danh sách tài liệu tham khảo
Cplusplus.com: https://cplusplus.com/
GeeksforGeeks: https://www.geeksforgeeks.org/
Phần B.
Bài 1
1 Cài đặt cấu trúc dữ liệu single list với bộ lặp xuôi với kiểu dữ liệu trừu tượng
2 Cài đặt class hàng hóa gồm tên hàng, số lượng, đơn giá các thao tác nhập xuất
3 Cài đặt class giỏ hàng với một danh sách liên kết đơn các hàng hóa cho phép thêm một hàng vào giỏ nếu có rồi thì tăng số lượng chưa có thì thêm mới vào cuối danh sách; bớt mặt hàng nếu bớt số lượng bằng 0 thì xóa khỏi giỏ.
Tính tiền giỏ hàng bằng tổng tiền của từng mặt hàng.
Xuất dữ liệu về giỏ hàng ra file văn bản hoadon.txt
Mô tả bài toán:
Trang 15Chúng ta cần xây dựng chương trình quản lý giỏ hàng (danh sách các mặt hàng) với các thao tác sau:
1 Thêm mặt hàng mới hoặc cập nhật số lượng nếu mặt hàng đã có trong giỏ.
2 Bớt mặt hàng: giảm số lượng một loại hàng, hoặc xóa mặt hàng khỏi giỏ nếu số lượng
còn lại bằng 0.
3 Hiển thị giỏ hàng: danh sách các mặt hàng với thông tin tên hàng, số lượng, đơn giá và
tổng tiền.
4 Xuất giỏ hàng ra file: lưu thông tin giỏ hàng vào file văn bản hoadon.txt.
Yêu cầu đầu vào và đầu ra:
o Yêu cầu nhập thêm hoặc bớt hàng từ giỏ.
o Số lượng loại mặt hàng cần bớt và thông tin từng loại.
2 Đầu ra:
o Danh sách giỏ hàng sau mỗi thao tác.
o File văn bản hoadon.txt chứa thông tin giỏ hàng.
Phân tích chức năng và cấu trúc dữ liệu
1 Các chức năng chính
Thêm hàng:
o Kiểm tra xem mặt hàng có tồn tại trong giỏ không.
o Nếu tồn tại, tăng số lượng.
Trang 16o Nếu không, thêm mặt hàng vào cuối danh sách.
Bớt hàng:
o Giảm số lượng một loại hàng.
o Nếu số lượng bằng 0 sau khi giảm, xóa mặt hàng khỏi danh sách.
soLuong: Số lượng hàng hóa.
donGia: Giá một đơn vị hàng.
o Phương thức:
nhap(): Nhập dữ liệu từ người dùng.
xuat(): Hiển thị dữ liệu hàng hóa.
tinhTien(): Tính tổng tiền (số lượng x đơn giá).
Node:
Trang 17o Dùng để tạo danh sách liên kết đơn (single linked list).
o Thuộc tính:
data: Chứa thông tin một mặt hàng (HangHoa).
next: Con trỏ trỏ đến nút tiếp theo.
themHang(hh): Thêm một mặt hàng vào giỏ.
botHang(tenHang, soLuong): Giảm số lượng hoặc xóa mặt hàng.
xuat(): Hiển thị danh sách hàng hóa.
xuatFile(): Xuất dữ liệu giỏ hàng ra file.
Phân tích thuật toán
1 Thêm mặt hàng ( themHang )
Nếu danh sách rỗng:
o Tạo một nút mới và đặt nó là head.
Nếu không:
o Duyệt qua danh sách để kiểm tra xem mặt hàng đã tồn tại chưa.
o Nếu tồn tại, tăng số lượng.
o Nếu không, thêm nút mới vào cuối danh sách.
2 Bớt mặt hàng ( botHang )
Trang 18 Duyệt danh sách:
o Tìm mặt hàng có tên khớp với tên cần bớt.
o Giảm số lượng theo yêu cầu.
o Nếu số lượng còn lại ≤ 0, xóa nút tương ứng khỏi danh sách.
3 Hiển thị giỏ hàng ( xuat )
Duyệt qua danh sách liên kết và in thông tin từng mặt hàng.
4 Xuất ra file ( xuatFile )
Mở file hoadon.txt để ghi.
Duyệt qua danh sách liên kết và ghi từng mặt hàng vào file.
Luồng hoạt động của chương trình
1 Nhập mặt hàng:
o Yêu cầu người dùng nhập thông tin mặt hàng (tên, số lượng, đơn giá).
o Gọi hàm themHang() để thêm mặt hàng vào giỏ.
2 Hiển thị giỏ hàng:
o Gọi hàm xuat() để in danh sách mặt hàng hiện có trong giỏ.
3 Bớt hàng:
o Nhập số lượng loại hàng cần bớt.
o Gọi hàm botHang() cho từng mặt hàng người dùng muốn bớt.
4 Xuất kết quả ra file:
o Gọi hàm xuatFile() để ghi thông tin giỏ hàng vào file hoadon.txt.
Phân tích các trường hợp đặc biệt
Trang 193 Xóa nút khi số lượng bằng 0:
o Nếu số lượng hàng hóa sau khi bớt = 0, nút chứa mặt hàng đó phải được xóa để đảm bảo danh sách gọn gàng.
HangHoa(string tenHang = "", int soLuong = 0, double donGia = 0)
: tenHang(tenHang), soLuong(soLuong), donGia(donGia) {}
Trang 20void xuat() const {
cout << tenHang << " | " << soLuong << " | " << donGia << " | " << tinhTien() << endl;
}
double tinhTien() const {
return soLuong * donGia;
}
};
Trang 21void themHang(const HangHoa& hh) {
Node* newNode = new Node(hh);
Trang 22}
temp->next = newNode;
}
}
void botHang(const string& tenHang, int soLuong) {
Node* temp = head;
while (temp != nullptr) {
Trang 23Node* temp = head;
while (temp->next && temp->next->data.tenHang != tenHang) { temp = temp->next;
Trang 24void xuat() const {
cout << "Ten hang | So luong | Don gia | Thanh tien\n";
Node* temp = head;
file << "Ten hang | So luong | Don gia | Thanh tien\n";
Node* temp = head;
while (temp) {
file << temp->data.tenHang << " | " << temp->data.soLuong << " | " << temp->data.donGia << " | " << temp->data.tinhTien() << endl;
Trang 25cin.ignore(); // Don dep bo dem sau khi nhap
if (tiepTuc == 'n' || tiepTuc == 'N') break;
}
Trang 26// Xuat gio hang ra man hinh
cout << "\nGio hang hien tai:\n";
cin.ignore(); // Don dep bo dem
for (int i = 0; i < soLuongCanBot; i++) {
Trang 27// Xuat lai gio hang sau khi bot
cout << "\nGio hang sau khi bot:\n";
4 Phân tích thời gian chạy của từng phương thức
1 Thêm hàng vào giỏ hàng ( themHang )
Cách hoạt động:
1 Duyệt qua danh sách để kiểm tra xem mặt hàng đã tồn tại hay chưa:
o Nếu tìm thấy, tăng số lượng.
o Nếu không tìm thấy, thêm một nút mới vào cuối danh sách.
Thời gian chạy:
Duyệt danh sách: O(n)O(n)O(n), vì trong trường hợp xấu nhất phải duyệt qua toàn bộ danh sách để kiểm tra.
Thêm nút mới vào cuối danh sách:
o Nếu đã duyệt đến cuối: O(1)O(1)O(1).
Tổng thời gian chạy trong trường hợp xấu nhất: O(n)O(n)O(n).
Trang 282 Bớt hàng trong giỏ hàng ( botHang )
Cách hoạt động:
1 Duyệt danh sách để tìm mặt hàng có tên khớp với tên cần bớt:
o Nếu tìm thấy, giảm số lượng.
o Nếu số lượng mới ≤ 0, gọi hàm xoaHang để xóa mặt hàng.
2 Nếu không tìm thấy, báo lỗi.
Thời gian chạy:
Duyệt danh sách để tìm mặt hàng: O(n)O(n)O(n).
Nếu cần xóa mặt hàng, gọi hàm xoaHang:
o Tìm nút cần xóa (có thể cần duyệt lại danh sách nếu không có thông tin vị trí): O(n)O(n)O(n).
1 Kiểm tra nếu nút đầu tiên (head\text{head}head) cần xóa:
o Nếu đúng, cập nhật head\text{head}head để trỏ đến nút kế tiếp và giải phóng bộ nhớ.
2 Nếu không, duyệt danh sách để tìm nút cần xóa:
o Cập nhật liên kết giữa nút trước đó và nút sau nút cần xóa.
o Giải phóng bộ nhớ.
Trang 29Thời gian chạy:
Trường hợp tốt nhất (xóa nút đầu tiên): O(1)O(1)O(1).
Trường hợp xấu nhất (xóa nút cuối cùng hoặc nút không tồn tại): O(n)O(n)O(n).
Tổng thời gian chạy: O(n)O(n)O(n) trong trường hợp xấu nhất.
4 Hiển thị giỏ hàng ( xuat )
Cách hoạt động:
1 Duyệt qua danh sách liên kết.
2 In thông tin từng nút (tên hàng, số lượng, đơn giá, thành tiền).
Thời gian chạy:
Duyệt qua danh sách: O(n)O(n)O(n).
In thông tin từng nút: O(1)O(1)O(1) cho mỗi nút.
Tổng thời gian chạy: O(n)O(n)O(n).
5 Xuất giỏ hàng ra file ( xuatFile )
Cách hoạt động:
1 Mở file và kiểm tra thành công.
2 Duyệt qua danh sách liên kết.
3 Ghi thông tin từng nút vào file.
Thời gian chạy:
Duyệt qua danh sách: O(n)O(n)O(n).
Ghi thông tin từng nút vào file: O(1)O(1)O(1) cho mỗi nút.
Tổng thời gian chạy: O(n)O(n)O(n).
Trang 305 Danh sách tài liệu tham khảo
"C++ Primer" - Stanley B Lippman, Josée Lajoie, Barbara E Moo
"Introduction to Algorithms" - Thomas H Cormen, Charles E Leiserson,
Ronald L Rivest, Clifford Stein
Hướng dẫn trực tuyến về Zeller’s Congruence
"Discrete Mathematics and Its Applications" - Kenneth H Rosen