ĐẠI HỌC ĐÀ NẴNG
TRƯỜNG ĐẠI HỌC BÁCH KHOA
KHOA CÔNG NGHỆ THÔNG TIN
ĐỒ ÁN
GIẢI THUẬT & LẬP TRÌNH
ĐỀ TÀI:
QUẢN LÝ HÀNG NHẬP TRONG THÁNG
SVTH :
Nhóm :
GVHD :
13.10
ĐỖ THỊ TUYẾT HOA
Đà Nẵng, 2016
MỤC LỤC
LỜI MỞ ĐẦU
Giải thuật và lập trình là học phần rất quan trọng cũng như không thể thiếu
đối với người lập trình. Môn học này được xem như nền tản cơ bản của lập trình
máy tính. Nó là cái nền và là cơ sở vững chắc để giải quyết các bài toán trong lập
trình, đồng thời cung cấp cho chúng ta hiểu biết về các giải thuật tác động lên dữ
liệu, cũng như cách tổ chức dữ liệu để giải quyết các bài toán sao cho hiệu quả và tối
ưu nhất.
Sau hai học phần lý thuyết và thực hành, chúng em nghiên cứu và thực hiện
đồ án này như là một cách để củng cố và mở rộng kiến thức. Thông qua quá trình
thực hiện đồ án, chúng em đã nắm bắt được những kỹ thuật quan trọng của việc
xây dựng cấu trúc dữ liệu và cách xây dựng một thuật toán sao cho tối ưu nhât.
Bài toán “Quản lý hàng nhập trong một tháng” mà chúng em nghiên cứu và
trình bày trong báo cáo sau đây là một trong những ví dụ.
Chúng em chân thành cảm ơn cô Đỗ Thị Tuyết Hoa đã giúp đỡ chúng em thực
hiện đồ án này. Và chúng em cũng rất mong sự góp ý, giúp đỡ từ cô để bài làm
chúng em được hoàn thiện hơn.
Nhóm sinh viên
Lê Trường Lâm
Trần Văn Thanh
Page 3
I.
Giới thiệu
Trong hệ thống bán hàng đơn lẻ hay to lớn đều đặt ra yêu cầu về tính toán lợi
nhuận cho mỗi thao tác giao dịch. Để quản lý được điều đó cần phải có một danh
sách cũng như một công cụ để lưu lại các dữ liệu giao dịch.
Nếu số lượng hàng hóa bạn nhập về không nhiều, chủng loại cũng không quá đa
dạng, quy mô kinh doanh lại nhỏ thì vấn đề quản lý hàng nhập không quá phức tạp.
Nhưng nếu ngược lại, bạn phải nhập hàng trăm lô hàng về mỗi tháng, thậm chí là
từng tuần, thì nhập kho thế nào để đảm bảo hàng hóa đủ số lượng, đạt chuẩn chất
lượng, và quản lý toàn bộ chúng theo cách thông thường thì không phải là dễ.
Chính vì vậy, chương trình quản lý hàng nhập trong một tháng đáp ứng được
phần nào các nhu cầu, khó khăn đề ra.
Sau đây là các thông tin của chương trình:
Thông tin phiếu nhập kho hàng gồm: mã hàng, tên hàng, đơn vị tính, ngày nhập,
số lượng, đơn giá, thành tiền.
Trong đó tính thành tiền (TT) = số lượng*đơn giá và được giảm theo qui ước:
Chương trình thực hiện các chức năng sau:
In danh sách các thông tin của tất cả các đối tượng.
Bổ sung thêm 1 đối tượng vào danh sách.
Tìm kiếm mẫu tin theo các tiêu chí khác nhau và hiển thị mẫu tin đó
Sắp xếp theo thứ tự tăng dần/ giảm dần
Chèn mẫu tin
Xóa 1 mẫu tin
In ra bảng thống kê theo từng ngày trong tháng gồm các cột: ngày nhập, tổng
số tiền
Xóa các mặt hàng theo thông tin cho trước
Page 4
II.
Phân tích bài toán
1. Dữ liệu vào
Thông tin hàng nhập bao gồm các trường:
Tên trường
Kiểu dữ liệu
Mã hàng
Tên hàng
Đơn vị hàng
Ngày nhập
Số lượng
Đơn giá
Thành tiền
char[7]
char[50]
char[40]
Int
Int
Int
Int
Bảng 1: Thông tin hàng nhập và kiểu dữ liệu
Dữ liệu này được lấy từ file HangNhap.txt
2. Dữ liệu ra
Dữ liệu có thể lưu lại vào file .txt nếu muốn.
Các thông tin theo yêu cầu bài toán:
0. In danh sách các thông tin của tất cả các đối tượng.
1. Bổ sung thêm 1 đối tượng vào danh sách, chèn mẫu tin sao cho mảng vẫn được
sắp theo thứ tự
2. In ra bảng thống kê theo từng ngày trong tháng gồm các cột: ngày nhập, tổng số
tiền
3. Sắp xếp theo thứ tự tăng dần/ giảm dần
4. Tìm kiếm mẫu tin theo các tiêu chí khác nhau và hiển thị mẫu tin đó
5. Xóa 1 mẫu tin
6. Thoát chương trình
III.
Thiết kế cấu trúc dữ liệu
Page 5
Các trường mẫu tin được liệt kê và phân biệt vào các biến thành viên của
struct HangNhap, mỗi biến tương ứng với các dữ liệu riêng phù hợ với đặc trưng
từng biến.
Cấu trúc dữ liệu hàng nhập trong một tháng:
Tên trường
Khai báo
Kiểu dữ liệu
Mã hàng
maHang
char[7]
Tên hàng
ten
char[50]
Đơn vị hàng
donVi
char[40]
Ngày nhập
ngayNhap
Int
Số lượng
soLuong
Int
Đơn giá
donGia
Int
Thành tiền
thanhTien
Int
Thực hiện khai báo:
typedef char MaHang[7];
typedef char Ten[50];
typedef char DonVi[40];
typedef int Ngay;
typedef int SoLuong;
typedef int DonGia;
typedef int ThanhTien;
typedef struct HangNhap
{
MaHang maHang;
Ten ten;
DonVi donVi;
Page 6
Ngay ngayNhap;
SoLuong soLuong;
DonGia donGia;
ThanhTien thanhTien;
} HN;
Tạo danh sách hàng nhập là một mảng danh sách đặc (danh sách đặc là danh
sách mà các phần tử được lưu trữ kế tiếp nhau trong bộ nhớ, phần tử thứ i được
lưu trữ ngay sau phần tử thứ i-1 giống như một mảng).
Khai báo mảng danh sách với số danh sách tối đa là MAXLIST = 100:
#define MAXLIST
HN A[MAXLIST];
Các biến liên quan khác:
int n; // là biến chứa nội dung là số phần tử thực trong danh sách hàng nhập
int ct; // Biến điều khiển các mục thực hiện chương trình (hiển thị, thống kê, tìm
kiếm,vv...)
Page 7
IV. Các giải thuật và tính độ phức tạp
1. Đọc dữ liệu từ file đưa và struct
File HangNhap.txt là file lưu trữ dữ liệu trong quá trình thực thi và sử dụng lâu
dài. Nó cũng như là một cơ sở dữ liệu đơn giản.
Hàm đọc file:
- Input: Dữ liệu trong file “HangNhap.txt”.
- Output: Dữ liệu đã được gia công trong struct và giá trị n các mẫu tin hàng
nhập.
- Cài đặt:
void read(HN A[], int &n){
char strHang[150]; // mảng lưu 1 dòng chuỗi khi đọc
int i = 0;
FILE *f = fopen("HangNhap.txt", "r");
fgets(strHang, 100, f); /* Đọc để loại bỏ dòng tiêu đề ban đầu của
file*/
// đọc và xử lý tách xâu từng dòng của file
while (!feof(f))
{ /* trong khi file chưa đọc hết thì còn thực hiện */
fgets(strHang, 100, f); // đọc 1 dòng đưa vào strHang
// tách chuỗi ra từng phần đưa vào các thành viên struct
strcpy(A[i].maHang, strtok(strHang, " "));
strcpy(A[i].ten, strtok(NULL, " "));
strcpy(A[i].donVi, strtok(NULL, " "));
A[i].ngayNhap = atoi(strtok(NULL, " "));
A[i].soLuong = atoi(strtok(NULL, " "));
A[i].donGia = atoi(strtok(NULL, " "));
A[i].thanhTien = atof(strtok(NULL, " "));
i++;
}
fclose(f); // sau khi đọc đóng file lại
n = i;
Page 8
}
- Tính độ phức tạp:
Nếu không kể các hàm xử lý xâu của thư viện “string.h” thì độ phức tạp của
giải thuật đọc dữ liệu là số hàng: O(n)
2. Ghi dữ liệu vào file
Các dữ liệu trong struct hiện hành được lưu vào trong file “HangNhap.txt”.
- Input: danh sách hàng nhập sau khi thực hiện các thao tác như nhập, bổ
sung, xóa
- Output: lưu lại các thay đổi vừa thự hiện vào file “HangNhap.txt”.
- Cài đặt:
void write(HN A[], int n){
int i;
FILE *f = fopen("HangNhap.txt", "w"); // mo file de ghi
if (f == NULL) thongBaoKhongLoadFile(); // neu file khong ton tai
// Ghi du lieu vao file
fprintf(f, "%3s%15s%10s%10s%10s%10s%10s",
"ID","TenHang", "DonVi", "NgayNhap", "SoLuong", "DonGia", "ThanhTien");
for (i = 0; i < n; i++) fprintf(f, "\n%3s%15s%10s%10d%10d%10d%10d",
A[i].maHang, A[i].ten, A[i].donVi, A[i].ngayNhap, A[i].soLuong, A[i].donGia,
A[i].thanhTien);
fclose(f);
// Dong file
}
- Tính độ phức tạp:
Thuật toán ghi file chỉ đơn giản là ghi n dòng từ ngăn xếp vào file và có độ
phức tạp là: O(n)
Page 9
3. Hàm nhập số
Để kiểm tra xem dữ liệu nhập vào có phải là số, hoặc rỗng hay không và trả
về số.
- Phạm vi áp dụng trong đề tài: Nhập dữ liệu từ bàn phím cho các biến
thành viên: ngayNhap, soLuong, donGia,...
- Input: Chuỗi ký tự
- Output: Nếu xâu nhập:
+ Rỗng hoặc không phải là một số thì trả về -1
+ Là một số trả về số đó.
- Cài đặt:
int nhapSo()
{
char str[20];
fflush(stdin);
gets(str);
if(strlen(str) == 0) return -1; //Nếu xâu nhập vào rỗng trả về -1
for(int i=0;i
if(str[i]<'0' || str[i]>'9') return -1; /*Nếu các phần tử trong xâu không
phải là số trả về -1 */
return atoi(str);
/* atoi(<string>) ham chuyen "chuoi so" sang "so"
*/
}
- Tính độ phức tạp:
Độ phức tạp số lần so sánh, tùy vào độ dài xâu nhập vào. Với xâu nhập vào có
độ lài len(xâu) = n thì độ phức tạp là O(n)
Page 10
4. Hiển thị danh sách
Hàm hiển thị thông tin của tất cả hàng nhập hiện tại trong tháng.
- Input: Danh sách hàng nhập hiện tại bao gồm: tên hàng, đơn vị tính, ngày
nhập, số lượng, thành tiền. Danh sách được lưu trữ trong file “HangNhap.txt”
- Out put: Hiển thị lên màn hình danh sách hiện tại của hàng nhập trong
tháng.
- Cài đặt:
void show(HN A[],int n)
{
printf("%5s%10s%10s%10s%10s%10s%10s\n",
"ID", "Holot", "Ten", "DonVi", "NgayNhap" , "SoLuong", "DonGia",
"ThanhTien");
for(int i = 0; i
printf("%5s%10s%10s%10d%10d%10d
%10d\n",A[i].maHang, A[i].ten, A[i].donVi, A[i].ngayNhap, A[i].soLuong,
A[i].donGia, A[i].thanhTien);
}
- Tính độ phức tạp:
Độ phức tạp của thuật toán trên là số lần in ra dữ liệu, số lần in ra là: n+1.
Độ phức tạp: O(n)
5. Bổ sung danh sách
Hàm bổ sung thêm một đối tượng hàng nhập vào danh sách.
-
Input: Danh sách hàng nhập hiện tại trong tháng và thông tin về hàng nhập
cần thêm vào danh sách.
-
Output: Danh sách hàng nhập trong tháng đã được bổ sung thêm đối tượng
-
Cài đặt:
int insertGUI(HN A[],int &n){
Page 11
int temp;
char str[20];
// Nhap Ma hang
while(1)
{
fflush(stdin);
gets(str);
if(strlen(str) != 0)
{
strcpy(A[n].maHang,str); break;
}
thongBao(" Ma hang khong duoc de trong !!! ");
}
// Nhap ten hang
while(1)
{
fflush(stdin);
gets(str);
if(strlen(str) != 0)
{
strcpy(A[n].ten,str); break;
}
thongBao(" Ten hang khong duoc de trong !!! ");
}
// Nhap don vi hang
while(1)
{
fflush(stdin);
gets(str);
if(strlen(str) != 0){
strcpy(A[n].donVi,str);
break;
}
thongBao(" Don vi hang khong duoc de trong !!! ");
}
// ngap ngay nhap
Page 12
while(1){
temp = nhapSo();
if(temp>0 && temp<31){
A[n].ngayNhap = temp;
break;
}
thongBao(" Ngay nhap hang khong hop le !!! ");
}
// nhap so luong hang
while(1)
{
temp = nhapSo();
if(temp>0){
A[n].soLuong = temp;
break;
}
thongBao(" So luong hang khong hop le !!! ");
}
// nhap don gia
while(1)
{
temp = nhapSo();
if(temp >= 0){
A[n].donGia = temp; break;
}
thongBao(" Don gia hang khong hop le !!! ");
}
double giam;
if (A[n].soLuong > 100) giam = 0.95;
else if (A[n].soLuong > 50) giam = 0.9;
else giam = 1;
A[n].thanhTien = double(A[n].soLuong * A[n].donGia * giam);
n++;
write(A,n);
}
- Tính độ phức tạp:
Page 13
Độ phức tạp của hàm insertGUI(HN A[],int &n) là tổng độ phức tạp của cá lần
nhập vào biến thành viên struct và hàm write(A,n).
Nếu tính tất cả các lần nhập đều đúng dữ liệu thì độ phức tạp của mỗi lần
nhập là n (trừ các lần nhập thẳng các xâu maHang, ten, donVi là 1), độ phức tạp
hàm write(A,n) là n.
Vậy độ phức tạp là: 3 + 5n => O(n)
6. Thống kê
Hàm thống kê và hiển thị ra màn hình thông tin về ngày nhập và tổng chi của
ngày đó trong tháng.
-
Input: Danh sách hàng nhập trong tháng.
-
Output: Danh sách gồm ngày nhập và tổng chi cả ngày đó.
-
Cài đặt:
void thongKe(HN A[], int n){
int i, j;
HN temp;
// sap xep theo ngay nhap
for (i = 1; i < n; i++)
for (j = 0; j < n - i; j++){
if (A[j].ngayNhap > A[j + 1].ngayNhap) {
temp = A[j];
A[j] = A[j + 1];
A[j + 1] = temp;
}
}
i = 0;
int tong = 0;
for (i = 0; i < n; i++) {
tong += A[i].thanhTien;
if (A[i].ngayNhap != A[i + 1].ngayNhap)
Page 14
{
printf("%40d",A[i].ngayNhap);
printf("%55d",tong);
tong = 0;
}
}
}
- Tính độ phức tạp:
Độ phức tạp của hàm thongKe(HN A[], int n) là tổng độ phức tạp của thuật
toán sắp xếp nổi bọt và thuật toán thống kê thành tiền.
Sắp xếp nổi bọt: Với mỗi i = 1,2,3,...,n-1 ta cần i phép so sánh. Do đó số lần so
sánh và đổi chổ trong giải thuật là:
Do đó độ phức tạp của giải thuật sắp xếp nổi bọt là: O(n 2)
Thuật toán thống kê hàng nhập nhờ vào dữ liệu đã xếp sẵn nên có độ phức
tạp là số lần so sánh và tính tổng của tất cả các mặt hàng: O(n)
Từ đó ta tính được độ phức tạp của hàm thongKe(HN A[], int n) là:
O(n2) + O(n) ~ O(n2)
7. Sắp xếp
Hàm sắp xếp sử dụng danh sách hàng nhập hiện có, thực hiện quá trình sắp
xếp và xuất ra một danh sách mới để tránh làm thay đổi dữ liệu hiện có. Danh
sách mới được sắp xếp hiển thị ra màn hình. Hàm được cài đặt sắp xếp dữ liệu
theo nhiều tiêu chí có trong cấu trúc dữ liệu hàng nhập, bao gồm: Mã hàng, Tên
hàng, Đơn vị, Ngày nhập, Số lượng, Đơn giá, Thành tiền.
-
Input: Danh sách hàng nhập hiện tại trong tháng.
-
Output: Danh sách hàng nhập đã được sắp xếp theo tiêu chí định trước.
Sau đây là hàm sắp xếp tăng dần, giảm dần theo Mã hàng. Các hàm khác tương
tự hàm này, chỉ thay đổi tham số truyền vào và cách thức so sánh cho các kiểu
dữ liệu vào.
-
Cài đặt:
Sắp xếp Mã hàng theo thứ tự tăng dần:
Page 15
void sortTang_maHang(HN A[], int &n){
int i, j;
HN temp;
for (i = 1; i < n; i++)
for (j = 0; j < n - i; j++){
if (strcmp(A[j].maHang, A[j + 1].maHang) > 0) {
temp = A[j];
A[j] = A[j + 1];
A[j + 1] = temp;
}
}
}
Sắp xếp mã hàng theo thứ tự giảm dần:
void sortGiam_maHang(HN A[], int &n){
int i, j;
HN temp;
for (i = 1; i < n; i++)
for (j = 0; j < n - i; j++){
if (layMaHang(A[j].maHang) < layMaHang(A[j +
1].maHang)) {
temp = A[j];
A[j] = A[j + 1];
A[j + 1] = temp;
}
}
}
Các hàm sắp xếp của đề tài sử dụng thuật toán sắp xếp nổi bọt.
Với mỗi i = 1,2,3,...,n-1 ta cần i phép so sánh. Do đó số lần so sánh và đổi chổ
trong giải thuật là:
Page 16
Do đó độ phức tạp của giải thuật sắp xếp nổi bọt là: O(n 2)
8. Tìm kiếm
Các hàm tìm kiếm mẫu tin với mục đích tìm kiếm theo yêu cầu của người sử
dụng.
-
Input: Danh sách hàng nhập hiện tại trong tháng và thông tin cần tìm kiếm.
-
Output: Thông tin trong hàng nhập tìm kiếm được.
Các hàm tìm kiếm theo nhiều tiêu chí khác nhau có trong cấu trúc dữ liệu hàng
nhập bao gồm: Mã hàng, Tên hàng, Đơn vị, Ngày nhập, Số lượng, Đơn giá,
Thành tiền.
-
Cài đặt:
Sau đây là hàm tìm kiếm theo Tên hàng. Các hàm khác tương tự chỉ thay
tham số truyền vào và kiểu dữ liệu:
void timKiem_ten(HN A[], int n){
char text[15];
int dem = 0;
fflush(stdin);
gets(text);
for (int i = 0; i < n; i++)
{
if (strcmp(A[i].ten, text) == 0)
{
showLine(A,i,dem); // in ra dòng hàng nhập tìm được
dem++;
}
}
if (dem == 0) thongBaoDuLieuKhongTonTai();
}
- Tính độ phức tạp:
Page 17
Dễ dàng thấy rằng thuật toán tìm kiếm này là số lần so sánh giữa thông tin
đầu vào và dữ liệu trong struct.
Độ phức tạp của giải thuật này là O(n)
9. Xóa
Hàm xóa thông tin về một hoặc một số mặt hàng theo tiêu chí mà người dung
muốn. Thuật toán sẽ thực hiện kiểm tra từng.
-
Input: Danh sách hàng nhập hiện tại
-
Output: Danh sách hàng nhập đã được xóa mặt hàng theo yêu cầu nhập vào
-
Cài đặt:
void deletes(HN A[], int &n)
{
int i = 0, soLanXoa = 0;
char maHang_temp[5],ten_temp[15],donVi_temp[8];
int ngayNhap_temp, soLuong_temp, donGia_temp,
thanhTien_temp;
gets(maHang_temp);
gets(ten_temp);
gets(donVi_temp);
ngayNhap_temp = nhapSo();
soLuong_temp = nhapSo();
donGia_temp = nhapSo();
thanhTien_temp = nhapSo();
while(1){
// Kiểm tra điều kiện đúng cho các mặt hàng được xóa
while (
!(
Page 18
// Đúng khi xâu có độ dài rỗng(tức là không có thông tin xóa)
hoặc là xâu có nội dung bằng dữ liệu thành viên struct
((strlen(maHang_temp) == 0) ? 1:!
strcmp(A[i].maHang,maHang_temp))
&&((strlen(ten_temp) == 0) ? 1: !strcmp(A[i].ten,ten_temp))
&&((strlen(donVi_temp) == 0) ? 1: !strcmp(A[i].donVi,donVi_temp))
&&((ngayNhap_temp == -1) ? 1: (A[i].ngayNhap ==
ngayNhap_temp))
&&((soLuong_temp == -1) ? 1: (A[i].soLuong == soLuong_temp))
&&((donGia_temp == -1) ? 1: (A[i].donGia == donGia_temp))
&&((thanhTien_temp == -1) ? 1: (A[i].thanhTien ==
thanhTien_temp))
)
&& i < n)
{
i++;
}
if (i == n) break;
for (int j = i + 1; j < n; j++) A[j - 1] = A[j];
n--;
soLanXoa++;
i++;
}
write(A,n);
if(soLanXoa)thongBaoXoaThanhCong(soLanXoa);
else thongBaoDuLieuKhongTonTai();
}
- Tính độ phức tạp:
Độ phức tạp của hàm deletes(HN A[], int &n) là tổng độ phức tạp giải thuật
xóa và ghi dữ liệu hàm write(A,n).
Page 19
Giải thuật xóa và ghi dữ liệu có độ phức tạp là O(n)
Vậy độ phức tạp của giải thuật xóa là O(n)
V. Kết quả chương trinh.
1. Menu chính:
Chứa các mục điều khiển quản lý hàng nhập
Điều khiển bằng các phím ↓ ↑ và chọn bằng phím ENTER
2. Hiển thị danh sách các hàng nhập
Hiển thị các trang lân cận bằng phím ↓ ↑
Nhấn phím INSERT để thêm thông tin. ESC để thoát.
Page 20
3. Thêm thông tin hàng nhập
Nhập các thông tin tương ứng các vùng, nếu nhập không đúng dữ liệu sẽ
có thông báo và yêu cầu nhập lại vùng đó.
Page 21
Page 22
4. Thống kê thành tiền hàng nhập theo các ngày trong tháng
5. Sắp sếp hàng nhập theo các tiêu chí được chọn
Page 23
6. Tìm kiếm và hiển thị hàng nhận
Trong menu “TIEU CHI TIM KIEM”, sử dụng ↑ ↓ ENTER để chọn mục
Nhấn phím Tap để chuyển sang “THONG TIN CAN TIM”
Page 24
7. Xóa hàng nhập:
Page 25