Hàng đợi
•
Cấu trúc dữ liệu hoạt động theo cơ chế first-in
first-out (FIFO)
•
Hai thao tác cơ bản:
–
Chèn vào hàng đợi: enqueue
–
Lấy ra khỏi hàng đợi: dequeue
•
Các đối tượng trong hàng đợi được sắp thứ tự
theo thời gian chúng được chèn vào hàng
•
Đối tượng được lấy ra khỏi hàng đợi là đối
tượng được chèn vào trước nhất
Hàng đợi
A B C D M N
head of queue tail of queue
enqueuedequeue
Hàng đợi, sử dụng mảng
Khai báo cấu trúc hàng đợi
Typerdef struct Queue
{
int *arrQueue;
int max;
int numItems;
int front;
int rear;
}
Hàng đợi, sử dụng mảng
Thao tác khởi tạo hàng đợi rỗng
int InitQueue(Queue &q, int maxItems)
{
q.arrQueue = new int(maxItems);
if(q.arrQueue == Null)
return 0; // không cấp phát được bộ nhớ
q.max = maxItems;
q.numItems = 0; // chưa có phần tử nào trong queue
q.front = q.rear = -1;
return 1; // khởi tạo thành công
}
Hàng đợi, sử dụng mảng
Thao tác kiểm tra hàng đợi rỗng
int IsEmpty(const Queue q)
{
if(q.numItems == 0)
return 1; // Queue rỗng
return 0; // Queue không rỗng
}
Hàng đợi, sử dụng mảng
Thao tác kiểm tra hàng đợi đầy
int IsFull(const Queue q)
{
if(q. numItems == q.max)
return 1; // Queue đầy
return 0; // Queue không đầy
}
Problem
•
Nếu mảng có kích thước là n, ta có:
•
Phải thực hiện 11 lần chèn vào, 9 lần lấy ra:
0
0 1
1
1 2
8 9
9
9
enqueue( 0 )
enqueue( 1 )
dequeue()
enqueue( 2 )
enqueue( 9 )
dequeue(8)
enqueue( 10 )
Trừu tượng mảng
Trừu tượng mảng
Giải pháp
•
Trở lại đầu dãy:
•
Yêu cầu:
–
front chỉ số đầu hàng đợi
–
rear chỉ số cuối hàng đợi
–
numItems biến đếm
–
array_size chiều dài mảng
10 9
enqueue( 10 )
Hàng đợi, sử dụng mảng
Thao tác EnQueue: thêm 1 phần tử vào cuối hàng đợi
int EnQueue(Queue &q, int newItem)
{
if (IsFull(q)) return 0; // Queue đầy, không thêm vào được
q.rear++;
if(q.rear == q.max) // tràn giá
q.rear = 0; // quay trở về đầu mảng
q.arrQueue[q.rear] = newItem; // thêm phần tử vào cuối Queue
if(q.numItems == 0) q.front = 0;
q.numItems++;
return 1; // thêm thành công
}
Hàng đợi, sử dụng mảng
Thao tác DeQueue: lấy ra 1 phần tử ở đầu hàng đợi
int DeQueue(Queue &q, int &itemout)
{
if (IsEmpty(q)) return 0; // Queue rỗng, không lấy ra được
itemout = q.arrQueue[q.front]; // lấy phần tử đầu ra
q.front++;
q.numItems ;
if(q.front == q.max) // nếu đi hết mảng …
q.front = 0; // … quay trở về đầu mảng
if(q.numItems == 0) q.front = q.rear = -1;
return 1; // xóa thành công
}
Hàng đợi, sử dụng mảng
Thao tác QueueFront: kiểm tra phần tử ở đầu hàng
đợi
int QueueFront(const Queue &q, int &itemout)
{
if (IsEmpty(q))
return 0;
// lấy phần tử đầu ra
itemout = q.arrQueue[q.front];
return 1;
}
Hàng đợi, sử dụng mảng
Thao tác QueueRear: kiểm tra phần tử ở cuối hàng
đợi
int QueueRear(const Queue &q, int &itemout)
{
if (IsEmpty(q))
return 0;
// lấy phần tử cuối ra
itemout = q.arrQueue[q.rear];
return 1;
}
Applications
•
Kiểu Client-server :
–
Một hoặc nhiều clients đang yêu cầu được phục vụ từ
một hay nhiều servers
–
Có thể có nhiều hơn một client đang đợi để được
phục vụ tại cùng thời điểm
–
Các clients trong hàng đợi sẽ được phục vụ theo theo
thứ tự thời gian chúng được chèn vào
Application
•
Một vài ứng dụng dễ nhìn thấy:
–
Kiểu client-server, khi mà có nhiều hơn một client gởi
yêu cầu phục vụ tới một Web server
–
Ví dụ, một (simple) web server chỉ có thể phục vụ mỗi
lần một yêu cầu
–
Rõ ràng có nhiều yêu cầu hầu như đồng thời được
gởi tới từ các trình duyệt
–
Yêu cầu đầu tiên sẽ được phục vụ, những yêu cầu
tiếp theo được đưa vào hàng đợi
Application
•
Một ứng dụng khác là thực hiện duyệt một cây
theo chiều ngang (breadth-first)
•
Cho trước một cây sau
Application
•
Giả sử ta muốn liệt kê tất cả nút theo trật tự
breadth-first
•
Ta liệt kê tất cả nút ở một mức trước khi xuống
mức tiếp theo
Application
•
Về điều này, ta cần một vài thuật ngữ:
–
Nút gốc (root node)
–
Nút con (child nodes hoặc children)
Application
•
Việc hiện thực dễ nhất là:
–
Đặt nút gốc vào hàng đợi
–
Khi hàng đợi không rỗng:
•
Lấy nút head ra
•
chèn tất cả con của nó vào hàng đợi
–
Trật tự của các phần tử được lấy ra khỏi hàng đợi gọi
là trật tự breadth-first
Application
•
Đưa nút gốc A vào
Application
•
Lấy A ra và đưa hai con của nó là B và H vào
Application
•
Lấy B ra và chèn C, D, và G
Application
•
Lấy H ra và đưa I là con của nó vào
Application
•
Lấy C ra – C không có con