Tải bản đầy đủ (.docx) (7 trang)

SỬ DỤNG cấu TRÚC HÀNG đợi để xây DỰNG hệ THỐNG QUẢN lý bán vé tàu

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (129.88 KB, 7 trang )

ĐỀ TÀI 1: SỬ DỤNG CẤU TRÚC HÀNG ĐỢI ĐỂ XÂY DỰNG HỆ THỐNG
QUẢN LÝ BÁN VÉ TÀU
I. KHÁI NIỆM HÀNG ĐỢI VÀ CÁC ĐẶC TRƯNG CỦA HÀNG ĐỢI
1. Khái niệm hàng đợi
Hàng đợi là một cấu trúc dữ liệu gần giống với ngăn xếp, nhưng khác với ngăn
xếp ở nguyên tắc chọn phần tử cần lấy ra khỏi tập phần tử.
Trái ngược với ngăn xếp, phần tử được lấy ra khỏi hàng đợi không phải là phần tử
mới nhất được đưa vào mà là phần tử đã được lưu trong hàng đợi lâu nhất. Quy luật này
của hàng đợi còn được gọi là Vào trước – Ra trước (First in – First out).
Như vậy ta có thể định nghĩa hàng đợi là một dạng đặc biệt của danh sách mà việc
lấy một phần tử ra được thực hiện ở 1 đầu (gọi là đầu hàng), còn việc bổ sung một phần
tử mới được thực hiện ở một đầu (gọi là cuối hàng).
2. Một số thao tác trong hàng đợi
-

Enqueue: thêm phần tử vào hàng đợi.

-

Dequeue: xóa phần tử khỏi hàng đợi.

-

Clear: xóa tất cả phần tử của hàng đợi.

-

Count: đếm số phần tử trong hàng đợi.

-


IsEmpty: kiểm tra hàng đợi có rỗng hay không.

3. Các đặc trưng của hàm đợi
Thứ tự mà mà theo đó các công việc trong hàng xếp được phục vụ gọi là quy tắc
phục vụ. Hầu như các hệ thống xếp hàng ngày nay được sử dụng để phục vụ khách hàng
theo trình tự mà chúng tới. Trình tự phục vụ đó là FIFS( First Come First Served). Ngoài
ra, còn có một số kiểu phục vụ khác như là:
-

LCFS( Last Come First Served) hay LIFO (Last In First Out): Theo đó các khách

hàng đến sau sẽ được phục vụ trước.
-

LCFSPR( LCFS With Pre- Emptive): Khi khách hàng đến sau nhất sẽ thế chỗ của

khách hàng đang được phục vụ xong thì phục vụ có thể tiếp tục đối với khách hàng bị thế
chỗ ngay nơi mà nó bị ngắt trước đây, trong trường hợp đó ta có dịch vụ với quyền ưu
tiên phục vụ trước – LIFOPR.


-

RR(Round Robin): Phục vụ vòng tròn, thời gian tại một tài nguyên được phân chia

thành một số khoản nhỏ có độ dài cố định và được gọi là các lượng tử.
II. THUẬT TOÁN
1.

Ý tưởng của thuật toán


Các khách hàng đến được sắp xếp vào hàng đợi đến lượt phục vụ mua vé tàu. Để đơn
giản ta thiết kế một hàng đợi. Các khách hàng được chọn để phục vụ theo nguyên tắc”
đến trước phục vụ trước” nghĩa là phục vụ cho khách hàng đứng đầu hàng. Khi khách
hàng đứng đầu hàng được phục vụ xong thì đến lượt khách hàng tiếp theo tiến hành thủ
tục mua vé. Khi có khách hàng mới đến mua vé thì sẽ được sắp xếp vào hàng đợi rỗng
hoặc hàng đợi chưa đầy.
Cần xây dựng các chức năng cần thiết cho chương trình:
-

Khởi tạo hàng đợi

-

Kiểm tra hàng đợi có rỗng không

-

Thêm một phần tử mới vào hàng, giả sử hàng đợi chưa đầy.

-

Loại một phần tử ra khỏi hàng, phần tử bị loại là phần tử đầu hàng, thường là phần

tử vừa được xử lý xong.
-

Xem phần tử tại đầu hàng

-


Phần tử đầu hàng được phục vụ trước

2.

Thuật toán

Queue là hàng đợi để lưu các phần tử, có quy tắc phần tử vào trước thì ra trước. Head là
vị trí của phần tử đầu tiên trong Queue. Coun: Lưu số lượng các phần tử trong Queue.
Thuật toán ta có thể viết riêng rẻ ra như sau, nếu muốn tổng hợp thì có thể gộp tuần tự
các đoạn lại với nhau.
1. Thêm phần tử vào hàng đợi.

B1: if(IsFull()) B3; else B2;
B2: Coun++; Jump(B4);
B3: printf(“Hàng đợi đã full”);
B4: Thoát chương trình.
2. Xóa một phần tử ra khỏi Queue.
B1: If(IsEmpty()) b4;else B2;
B2: Queue[Head].check = false;


B3: Head = (Head+1)%MAX; Coun--; Jump(B5);
B4: printf(“Hàng đợi đã Empty”);
B5: Thoát chương trình.
3. Kiểm tra hàng đợi có Empty hay không?
B1: if(Coun<=0) return true; else return false;
4. Kiểm tra hàng đợi có Full hay không?
B1: if(Coun>MAX) return true; else return false;
5. In một phần tử x của Queue.

3. Đánh giá độ phức tạp của thuật toán
- Độ phức tạp của câu lệnh: O(1)
- Độ phức tạp của vòng for nhỏ bao câu lệnh: O(n)
Áp dụng quy tắc 4 (quy tắc nhân) T(n) = O(1..n) = O(n).
Vậy độ phức tạp của thuật toán là O(n).
III. CHƯƠNG TRÌNH MINH HỌA
Đầu tiên khai báo thư viện mà ta sử dụng để chứa các lớp: List.h
#include <stdlib.h>
#include "list.h"
+ Thao tác khởi tạo hàng đợi: Tạo hàng đợi có tên là l. Thực hiện việc gán giá trị bằng
NULL cho biến head, giá trị NULL cho biến tail và giá trị 0 cho biến count, cho biết
hàng đợi đang ở trạng thái rỗng. Biến count cho biết số phần tử hiện tại của hàng đợi để
thuận tiện cho việc kiểm tra hàng đợi đầy hoặc rỗng. Khi chúng ta cần 1 chuỗi có kích
thước của danh sách hàng đợi vì thế cần phải xin số ô nhớ đủ cho kích thước của hàng
đợi bằng lệnh malloc(sizeof(list)).
list* list_create() {
list *l = (list*)malloc(sizeof(list));
l->head = NULL;
l->tail = NULL;
l->count = 0;
return l;
}


+ Thao tác kiểm tra hàng đợi: dùng hàm trả về giá trị True hoặc false để kiểm tra hàng
đợi, nếu số phần tử bằng 0, giá trị count bằng 0 thì trả về kết quả là đúng (True)-> hàng
đợi rỗngcòn không thì trả về kết quả sai (False) -> hàng đợi không rỗng.
bool list_isNull(list *pl) {
if (pl->count == 0) return true;
else return false;

}
+ Thao tác thêm vào hàng đợi: thêm 1 phần tử mới vào cuối hàng đợi (giả sử hàng đợi
chưa đầy). Cấp phát bộ nhớ cho phần tử mới. Gán giá trị NULL cho phần tử tiếp theo
của hàng đợi. Gán giá trị value cho phần tử mới.
void list_push_end(list *pl, void *value) {
node *p = (node*)malloc(sizeof(node));
p->next = NULL;
p->value = value;
if (pl->tail == NULL)
pl->head = p;
else
pl->tail->next = p;
pl->tail = p;
pl->count++;
}
+ Thao tác kiểm tra hàng đợi: sau khi thêm phần tử, kiểm tra hàng đợi đã đầy chưa.
void list_remove_head(list *pl) {
node *p = pl->head;
pl->head = p->next;
pl->count--;
free(p);
if (pl->head == NULL)
pl->tail = NULL;
}
+ Thao tác loại bỏ 1 phần tử ra khỏi hàng đợi: bắt đầu thực hiện thao tác loại bỏ
phần tử đầu tiên của hàng đợi.
void* list_pop_begin(list *pl) {
if (pl->head == NULL)
return NULL;



void *v = pl->head->value;
list_remove_head(pl);
return v;
}
+ Thao tác xem phần tử đầu: thực hiện thao tác xem phần tử đầu, nếu phần tử đầu có
giá trị NULL thì trả về kết quả hàng đợi là NULL, nếu không thì phần tử mới là phần tử
đầu tiên của hàng đợi.
void* list_begin(list *pl) {
if (pl->head == NULL)
return NULL;
return pl->head->value;
}
+ Thao tác hiển thị các phần tử trong hàng đợi
void list_clear(list *pl) {
node *p = pl->head;
while (p) {
pl->head = p->next;
free(p);
p = pl->head;
}
pl->tail = NULL;
pl->count = 0;
}
+ Thao tác hủy hàng đợi: thực hiện thao tác hủy hàng đợi.
void list_destroy(list *pl) {
list_clear(pl);
free(pl);
}
- Sau đó, để thực định nghĩa các thao tác : List.cpp

#ifndef __LIST_H
#define __LIST_H
#include <stdlib.h>
typedef struct node_s {
void *value;
node_s *next;
} node;


typedef struct list_s {
node *head, *tail;
int count;
} list;
list* list_create();
bool list_isNull(list *pl);
void list_push_end(list *pl, void *value);
void list_remove_head(list *pl);
void* list_pop_begin(list *pl);
void* list_begin(list *pl);
void list_clear(list *pl);
void list_destroy(list *pl);
#endif
-

Đây là đoạn code thực thi chương trình: main.cpp

#include <stdio.h>
#include "list.h"
int main() {
int soLuong = 9;

int khach_hang[] = { 1,3,5,77,9,2,4,6,8 };
// Khoi tao
list *queue = list_create();
// kiem tra queue
bool b = list_isNull(queue);
// Them vao queue
for (int i = 0; i < soLuong; i++) {
list_push_end(queue, khach_hang + i);
}


// kiem tra queue
b = list_isNull(queue);
// so luong
int soLuongQueue = queue->count;
// Loai bo mot phan tu ra queue
list_pop_begin(queue);
// kiem tra so luong sau khi loai bo
soLuongQueue = queue->count;
// Xem phan tu dau
int phanTuDau = *(int*)list_begin(queue);
printf("Phan tu dau: %d\n", phanTuDau);
// Hien thi cac phan tu trong queue
printf("Cac phan tu co trong queue: ");
for (int i = 0; i < soLuongQueue; i++) {
int *v = (int*)list_pop_begin(queue);
printf("%d ", *v);
}
// Huy queue
list_destroy(queue);

//
printf("\n");
system("pause");
return 0;
}



×