Queue Basic
1. Giới thiệu hàng đợi
Hàng đợi (Queue): Là một cấu trúc dữ liệu dạng danh sách tuyến tính, chỉ cho phép thực hiện thêm phần tử vào một đầu của danh sách và xóa phần tử từ đầu kia của danh sách.
Chúng ta gọi đầu cho phép thêm là "đuôi (rear)"; và đầu cho phép xóa là "đầu (front)". Khi danh sách không có phần tử nào, chúng ta gọi nó là "hàng đợi rỗng".
Hàng đợi có hai hoạt động cơ bản: "thêm phần tử (enqueue)" và "xóa phần tử (dequeue)".
- Hoạt động thêm phần tử vào hàng đợi còn được gọi là "enqueue".
- Hoạt động xóa phần tử khỏi hàng đợi còn được gọi là "dequeue".
Đơn giản mà nói, hàng đợi là một danh sách tuyến tính tuân theo nguyên tắc "vào trước ra trước (First In First Out)", viết tắt là "FIFO".
Chúng ta có thể giải thích định nghĩa của hàng đợi từ hai khía cạnh:
- Khía cạnh đầu tiên là "danh sách tuyến tính".
Hàng đợi đầu tiên là một danh sách tuyến tính, các phần tử trong hàng đợi có mối quan hệ tuyến tính với nhau. Các phần tử trong hàng đợi được thêm vào theo tuần tự . Phần tử đầu tiên trong hàng đợi là , phần tử cuối cùng trong hàng đợi là .
- Khía cạnh thứ hai là "nguyên tắc vào trước ra trước".
Theo định nghĩa của hàng đợi, phần tử vào hàng đợi trước nhất sẽ ở đầu hàng đợi, phần tử vào hàng đợi sau cùng sẽ ở cuối hàng đợi. Mỗi lần xóa phần tử khỏi hàng đợi, chúng ta luôn xóa phần tử ở đầu hàng đợi, tức là phần tử vào hàng đợi trước nhất. Nghĩa là, việc thêm phần tử vào hàng đợi hoặc xóa phần tử khỏi hàng đợi được thực hiện theo nguyên tắc " vào trước ra trước".
2. Hàng đợi lưu trữ theo tuần tự và lưu trữ theo liên kết
Tương tự như danh sách tuyến tính, hàng đợi có hai phương pháp lưu trữ: "hàng đợi lưu trữ theo tuần tự" và "hàng đợi lưu trữ theo liên kết".
- "Hàng đợi lưu trữ theo tuần tự": Sử dụng một nhóm các đơn vị lưu trữ liên tiếp để lưu trữ các phần tử trong hàng đợi từ đầu đến cuối. Đồng thời sử dụng con trỏ
front
để chỉ đến vị trí của phần tử đầu hàng đợi trong hàng đợi, và sử dụng con trỏrear
để chỉ đến vị trí của phần tử cuối hàng đợi trong hàng đợi. - "Hàng đợi lưu trữ theo liên kết": Sử dụng danh sách liên kết đơn để triển khai hàng đợi. Các phần tử trong hàng đợi được thêm vào sau nút đầu tiên của danh sách và sử dụng con trỏ
front
để chỉ đến vị trí của phần tử đầu hàng đợi, vàrear
chỉ đến vị trí của phần tử cuối hàng đợi.
Lưu ý: Vị trí mà front
và rear
chỉ đến không hoàn toàn cố định. Đôi khi, để thuận tiện trong thiết kế thuật toán và viết mã ngắn gọn, front
có thể chỉ đến vị trí trước phần tử đầu hàng đợi. rear
cũng có thể chỉ đến vị trí sau phần tử cuối hàng đợi. Cụ thể phụ thuộc vào cách triển khai thuật toán.
2.2 Triển khai hàng đợi lưu trữ theo tuần tự
Cách đơn giản nhất để triển khai hàng đợi là sử dụng một mảng để lưu trữ các phần tử theo tuần tự. Trong Python
, chúng ta có thể sử dụng danh sách (list
) để triển khai.
2.2.1 Mô tả cơ bản của hàng đợi lưu trữ theo tuần tự
Để thuận tiện cho thiết kế thuật toán và mã ngắn gọn, chúng ta định nghĩa rằng: con trỏ self.front
trỏ đến vị trí trước phần tử đầu hàng đợi, và con trỏ self.rear
trỏ đến vị trí sau phần tử cuối hàng đợi.
- Khởi tạo hàng đợi rỗng: Tạo một hàng đợi rỗng
self.queue
, định nghĩa kích thước hàng đợiself.size
. Đặt con trỏself.front
vàself.rear
đều trỏ đến-1
. Tức làself.front = self.rear = -1
. - Kiểm tra hàng đợi có rỗng hay không: Dựa vào vị trí mà con trỏ
self.front
vàself.rear
trỏ đến để kiểm tra. Nếu con trỏself.front
vàself.rear
trỏ đến cùng một vị trí, thì hàng đợi rỗng. Ngược lại, hàng đợi không rỗng. - Kiểm tra hàng đợi đã đầy hay chưa: Nếu con trỏ
self.rear
trỏ đến vị trí cuối cùng của hàng đợi, tức làself.rear == self.size - 1
, thì hàng đợi đã đầy. Ngược lại, hàng đợi chưa đầy. - Thêm phần tử (nhập hàng): Trước tiên kiểm tra hàng đợi đã đầy chưa, nếu đã đầy thì ném ra ngoại lệ. Nếu hàng đợi chưa đầy, di chuyển con trỏ
self.rear
sang phải một vị trí và gán giá trị. Lúc này, con trỏself.rear
trỏ đến phần tử cuối hàng đợi. - Xóa phần tử (xuất hàng): Trước tiên kiểm tra hàng đợi có rỗng hay không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, gán giá trị của phần tử đầu hàng đợi (tại vị trí
self.front + 1
) bằngNone
và di chuyển con trỏself.front
sang phải một vị trí. - Lấy giá trị phần tử đầu hàng đợi: Trước tiên kiểm tra hàng đợi có rỗng hay không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, vì con trỏ
self.front
trỏ đến vị trí trước phần tử đầu hàng đợi, nên phần tử đầu hàng đợi nằm ở vị trí sauself.front
, trả vềself.queue[self.front + 1]
. - Lấy giá trị phần tử cuối hàng đợi: Trước tiên kiểm tra hàng đợi có rỗng hay không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, vì con trỏ
self.rear
trỏ đến vị trí sau phần tử cuối hàng đợi, nên trả vềself.queue[self.rear]
.
2.2.2 Mã nguồn triển khai hàng đợi lưu trữ theo tuần tự
class Queue:
# Khởi tạo hàng đợi rỗng
def __init__(self, size=100):
self.size = size
self.queue = [None for _ in range(size)]
self.front = -1
self.rear = -1
# Kiểm tra hàng đợi có rỗng hay không
def is_empty(self):
return self.front == self.rear
# Kiểm tra hàng đợi đã đầy hay chưa
def is_full(self):
return self.rear + 1 == self.size
# Thêm phần tử (enqueue)
def enqueue(self, value):
if self.is_full():
raise Exception('Hàng đợi đã đầy')
else:
self.rear += 1
self.queue[self.rear] = value
# Xóa phần tử (dequeue)
def dequeue(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
self.front += 1
return self.queue[self.front]
# Lấy giá trị phần tử đầu hàng đợi
def front_value(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
return self.queue[self.front + 1]
# Lấy giá trị phần tử cuối hàng đợi
def rear_value(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
return self.queue[self.rear]
2.3 Triển khai hàng đợi lưu trữ vòng theo tuần tự
Trong phần "2.2 Cài đặt lưu trữ tuần tự của hàng đợi", nếu tất cả các vị trí từ 0
đến size - 1
trong hàng đợi đều được các phần tử chiếm dụng, thì hàng đợi đã đầy (tức là self.rear == self.size - 1
), và thực hiện thêm phần tử vào hàng đợi sẽ gây ra ngoại lệ hàng đợi đã đầy.
Tuy nhiên, do thao tác xóa phần tử luôn xóa phần tử đầu hàng đợi và di chuyển self.front
sang phải, trong khi thao tác chèn phần tử lại luôn được thực hiện ở cuối hàng đợi. Qua các thao tác xóa và chèn, hàng đợi di chuyển như là di chuyển toàn bộ hàng đợi sang phải.
Khi con trỏ hàng đợi đến self.size - 1
thỏa mãn điều kiện self.rear == self.size - 1
, thì thêm phần tử vào hàng đợi từ vị trí 0
nếu vẫn còn không gian trống phía trước.
Có hai cách để giải quyết vấn đề "tràn giả (pseudo-overflow)":
- Cách thứ nhất: Sau mỗi lần xóa phần tử đầu hàng đợi, di chuyển toàn bộ các phần tử trong hàng đợi sang trái
1
vị trí. Đoạn mã như sau:
# Thao tác xóa
def dequeue(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
value = self.queue[0]
for i in range(self.rear):
self.queue[i] = self.queue[i + 1]
return value
Trong trường hợp này, con trỏ đầu hàng đợi dường như không cần thiết vì con trỏ đầu hàng đợi luôn ở vị trí 0
của hàng đợi. Tuy nhiên, vì thao tác xóa liên quan đến việc di chuyển toàn bộ các phần tử trong hàng đợi, thời gian thực hiện của thao tác xóa sẽ tăng từ lên . Vì vậy, cách tiếp cận này không phải là lựa chọn tốt.
- Cách thứ hai: Tưởng tượng hàng đợi như một danh sách liên kết tuần hoàn, sử dụng phép toán modulo trong toán học để tái sử dụng không gian. Điều này giải quyết vấn đề "tràn giả (pseudo-overflow)".
Khi thực hiện thao tác chèn, nếu vị trí self.size - 1
trong hàng đợi đã được chiếm dụng, chỉ cần vẫn còn không gian trống phía trước, phần tử mới sẽ được chèn vào từ vị trí 0
.
Chúng ta đặt: self.size
là số lượng phần tử tối đa của hàng đợi tuần hoàn. Con trỏ đầu hàng đợi self.front
trỏ vào vị trí trước phần tử đầu hàng đợi, trong khi con trỏ cuối hàng đợi self.rear
trỏ vào vị trí của phần tử cuối hàng đợi.
- Khởi tạo hàng đợi rỗng: Tạo một hàng đợi rỗng, định nghĩa kích thước hàng đợi là
self.size + 1
. Đặt con trỏ đầu hàng đợiself.front
và con trỏ cuối hàng đợiself.rear
đều trỏ vào0
, tức làself.front = self.rear = 0
. - Kiểm tra hàng đợi có rỗng hay không: Dựa trên vị trí mà con trỏ đầu hàng đợi
self.front
và con trỏ cuối hàng đợiself.rear
trỏ đến để kiểm tra. Theo thỏa thuận, nếu con trỏ đầu hàng đợiself.front
và con trỏ cuối hàng đợiself.rear
trùng nhau, thì hàng đợi rỗng. Ngược lại, hàng đợi không rỗng. - Kiểm tra hàng đợi có đầy hay không: Con trỏ đầu hàng đợi ở vị trí sau con trỏ cuối hàng đợi, tức là
(self.rear + 1) % self.size == self.front
, thì hàng đợi đã đầy. Ngược lại, hàng đợi chưa đầy. - Chèn phần tử (thêm vào cuối hàng đợi): Trước tiên, kiểm tra hàng đợi đã đầy chưa, nếu đã đầy thì ném ra ngoại lệ. Nếu chưa đầy, di chuyển con trỏ cuối hàng đợi
self.rear
sang phải1
vị trí và thực hiện phép gán. Lúc này, con trỏ cuối hàng đợiself.rear
trỏ vào phần tử cuối hàng đợi. - Xóa phần tử (xóa phần tử đầu hàng đợi): Trước tiên, kiểm tra hàng đợi có rỗng không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, gán giá trị
None
cho phần tử mà con trỏ đầu hàng đợiself.front
trỏ vào và di chuyển con trỏ đầu hàng đợiself.front
sang phải1
vị trí. - Lấy phần tử đầu hàng đợi: Trước tiên, kiểm tra hàng đợi có rỗng không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, vì con trỏ đầu hàng đợi
self.front
trỏ vào vị trí trước phần tử đầu hàng đợi, nên phần tử đầu hàng đợi nằm ở vị trí sauself.front
, trả vềself.queue[(self.front + 1) % self.size]
. - Lấy phần tử cuối hàng đợi: Trước tiên, kiểm tra hàng đợi có rỗng không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, vì con trỏ cuối hàng đợi
self.rear
trỏ vào vị trí cuối hàng đợi, nên trả vềself.queue[self.rear]
.
2.3.1 Mô tả cơ bản của lưu trữ tuần hoàn của hàng đợi
Dưới đây là mô tả cơ bản của lưu trữ tuần hoàn của hàng đợi:
Chúng ta đặt: self.size
là số lượng phần tử tối đa của hàng đợi tuần hoàn. Con trỏ đầu hàng đợi self.front
trỏ vào vị trí trước phần tử đầu hàng đợi, trong khi con trỏ cuối hàng đợi self.rear
trỏ vào vị trí của phần tử cuối hàng đợi.
- Khởi tạo hàng đợi rỗng: Tạo một hàng đợi rỗng, định nghĩa kích thước hàng đợi là
self.size + 1
. Đặt con trỏ đầu hàng đợiself.front
và con trỏ cuối hàng đợiself.rear
đều trỏ vào0
, tức làself.front = self.rear = 0
. - Kiểm tra hàng đợi có rỗng hay không: Dựa trên vị trí mà con trỏ đầu hàng đợi
self.front
và con trỏ cuối hàng đợiself.rear
trỏ đến để kiểm tra. Theo thỏa thuận, nếu con trỏ đầu hàng đợiself.front
và con trỏ cuối hàng đợiself.rear
trùng nhau, thì hàng đợi rỗng. Ngược lại, hàng đợi không rỗng. - Kiểm tra hàng đợi có đầy hay không: Con trỏ đầu hàng đợi ở vị trí sau con trỏ cuối hàng đợi, tức là
(self.rear + 1) % self.size == self.front
, thì hàng đợi đã đầy. Ngược lại, hàng đợi chưa đầy. - Chèn phần tử (thêm vào cuối hàng đợi): Trước tiên, kiểm tra hàng đợi đã đầy chưa, nếu đã đầy thì ném ra ngoại lệ. Nếu chưa đầy, di chuyển con trỏ cuối hàng đợi
self.rear
sang phải1
vị trí và thực hiện phép gán. Lúc này, con trỏ cuối hàng đợiself.rear
trỏ vào phần tử cuối hàng đợi. - Xóa phần tử (xóa phần tử đầu hàng đợi): Trước tiên, kiểm tra hàng đợi có rỗng không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, gán giá trị
None
cho phần tử mà con trỏ đầu hàng đợiself.front
trỏ vào và di chuyển con trỏ đầu hàng đợiself.front
sang phải1
vị trí. - Lấy phần tử đầu hàng đợi: Trước tiên, kiểm tra hàng đợi có rỗng không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, vì con trỏ đầu hàng đợi
self.front
trỏ vào vị trí trước phần tử đầu hàng đợi, nên phần tử đầu hàng đợi nằm ở vị trí sauself.front
, trả vềself.queue[(self.front + 1) % self.size]
. - Lấy phần tử cuối hàng đợi: Trước tiên, kiểm tra hàng đợi có rỗng không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, vì con trỏ cuối hàng đợi
self.rear
trỏ vào vị trí cuối hàng đợi, nên trả vềself.queue[self.rear]
.
2.3.2 Mã nguồn triển khai lưu trữ của hàng đợi vòng theo tuần tự
class Queue:
# Khởi tạo hàng đợi rỗng
def __init__(self, size=100):
self.size = size + 1
self.queue = [None for _ in range(size + 1)]
self.front = 0
self.rear = 0
# Kiểm tra hàng đợi có rỗng hay không
def is_empty(self):
return self.front == self.rear
# Kiểm tra hàng đợi có đầy hay không
def is_full(self):
return (self.rear + 1) % self.size == self.front
# Thêm phần tử vào cuối hàng đợi
def enqueue(self, value):
if self.is_full():
raise Exception('Hàng đợi đã đầy')
else:
self.rear = (self.rear + 1) % self.size
self.queue[self.rear] = value
# Xóa phần tử đầu hàng đợi
def dequeue(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
self.queue[self.front] = None
self.front = (self.front + 1) % self.size
return self.queue[self.front]
# Lấy phần tử đầu hàng đợi
def front_value(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
value = self.queue[(self.front + 1) % self.size]
return value
# Lấy phần tử cuối hàng đợi
def rear_value(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
value = self.queue[self.rear]
return value
2.3 Cài đặt hàng đợi lưu trữ theo liên kết
Đối với cấu trúc dữ liệu có sự thay đổi dữ liệu lớn trong quá trình sử dụng, hoặc thực hiện thao tác chèn và xóa thường xuyên, cấu trúc lưu trữ dựa trên liên kết phù hợp hơn so với lưu trữ tuần tự.
Vì vậy, chúng ta có thể sử dụng cấu trúc lưu trữ dựa trên liên kết để triển khai hàng đợi.
- Chúng ta sử dụng một danh sách liên kết tuyến tính để biểu diễn hàng đợi, trong đó mỗi phần tử trong hàng đợi tương ứng với một nút liên kết trong danh sách liên kết.
- Chúng ta đặt nút đầu tiên của danh sách liên kết là con trỏ đầu hàng đợi
front
và xác định con trỏ cuối hàng đợirear
là con trỏ tới nút cuối cùng của danh sách liên kết. - Cuối cùng, chúng ta giới hạn chỉ có thể thực hiện thao tác xóa ở đầu danh sách liên kết và thao tác chèn ở cuối danh sách liên kết, từ đó tạo thành một hàng đợi.
2.3.1 Mô tả cơ bản của hàng đợi lưu trữ theo liên kết
Chúng ta đặt: con trỏ đầu hàng đợi self.front
trỏ vào vị trí trước phần tử đầu hàng đợi, trong khi con trỏ cuối hàng đợi self.rear
trỏ vào vị trí của phần tử cuối hàng đợi.
- Khởi tạo hàng đợi rỗng: Tạo một nút đầu tiên của danh sách liên kết
self.head
, đặt con trỏ đầu hàng đợiself.front
và con trỏ cuối hàng đợiself.rear
đều trỏ vàohead
. Tức làself.front = self.rear = head
. - Kiểm tra hàng đợi có rỗng hay không: Dựa trên vị trí mà con trỏ đầu hàng đợi
self.front
và con trỏ cuối hàng đợiself.rear
trỏ đến để kiểm tra. Theo thỏa thuận, nếu con trỏ đầu hàng đợiself.front
bằng con trỏ cuối hàng đợiself.rear
, thì hàng đợi rỗng. Ngược lại, hàng đợi không rỗng. - Chèn phần tử (thêm vào cuối hàng đợi): Tạo một nút liên kết với giá trị
value
, chèn vào cuối danh sách liên kết và di chuyển con trỏ cuối hàng đợiself.rear
theo danh sách liên kết1
vị trí đến cuối danh sách liên kết. Lúc này, con trỏ cuối hàng đợiself.rear
trỏ vào phần tử cuối hàng đợi. - Xóa phần tử (xóa phần tử đầu hàng đợi): Trước tiên, kiểm tra hàng đợi có rỗng không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, lấy nút liên kết tiếp theo của con trỏ đầu hàng đợi
self.front
và di chuyển con trỏ đầu hàng đợiself.front
theo danh sách liên kết1
vị trí. Nếu nút liên kết tiếp theo của con trỏ đầu hàng đợiself.front
là con trỏ cuối hàng đợiself.rear
, thì hàng đợi rỗng, lúc này, gán con trỏ cuối hàng đợiself.rear
bằng con trỏ đầu hàng đợiself.front
. - Lấy phần tử đầu hàng đợi: Trước tiên, kiểm tra hàng đợi có rỗng không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, vì con trỏ đầu hàng đợi
self.front
trỏ vào vị trí trước phần tử đầu hàng đợi, nên phần tử đầu hàng đợi nằm ở vị trí sauself.front
, trả vềself.front.next.value
. - Lấy phần tử cuối hàng đợi: Trước tiên, kiểm tra hàng đợi có rỗng không, nếu rỗng thì ném ra ngoại lệ. Nếu không rỗng, vì con trỏ cuối hàng đợi
self.rear
trỏ vào vị trí cuối hàng đợi, nên trả vềself.rear.value
.
2.3.2 Mã cài đặt lưu trữ chuỗi của hàng đợi
class Node:
def __init__(self, value):
self.value = value
self.next = None
class Queue:
# Khởi tạo hàng đợi rỗng
def __init__(self):
head = Node(0)
self.front = head
self.rear = head
# Kiểm tra hàng đợi có rỗng hay không
def is_empty(self):
return self.front == self.rear
# Thêm phần tử vào cuối hàng đợi
def enqueue(self, value):
node = Node(value)
self.rear.next = node
self.rear = node
# Xóa phần tử đầu hàng đợi
def dequeue(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
node = self.front.next
self.front.next = node.next
if self.rear == node:
self.rear = self.front
value = node.value
del node
return value
# Lấy phần tử đầu hàng đợi
def front_value(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
return self.front.next.value
# Lấy phần tử cuối hàng đợi
def rear_value(self):
if self.is_empty():
raise Exception('Hàng đợi rỗng')
else:
return self.rear.value
3. Ứng dụng của hàng đợi
Hàng đợi là một cấu trúc dữ liệu phụ được sử dụng rộng rãi trong các thuật toán và chương trình. Nó có nhiều ứng dụng trong cuộc sống hàng ngày như xếp hàng mua vé, giao dịch ngân hàng và đăng ký dịch vụ.
Ứng dụng của hàng đợi trong lĩnh vực khoa học máy tính chủ yếu được thể hiện ở hai khía cạnh sau:
Giải quyết vấn đề không khớp tốc độ giữa máy chủ và thiết bị ngoại vi.
- Ví dụ: Giải quyết vấn đề không khớp tốc độ giữa máy chủ và máy in. Khi máy chủ gửi dữ liệu đến máy in, tốc độ gửi dữ liệu nhanh hơn tốc độ in, nếu gửi dữ liệu trực tiếp đến máy in sẽ không hiệu quả. Do đó, có thể thiết lập một hàng đợi lưu trữ dữ liệu in, dữ liệu sẽ được ghi vào hàng đợi theo tuần tự và máy in sẽ lấy dữ liệu từ hàng đợi theo nguyên tắc "vào trước ra trước". Điều này đảm bảo việc in dữ liệu đúng và tăng hiệu suất của máy chủ.
Giải quyết vấn đề cạnh tranh tài nguyên hệ thống do nhiều người dùng gây ra.
- Ví dụ: Trong một hệ thống máy tính với nhiều thiết bị đầu cuối, khi nhiều người dùng cần chạy các chương trình riêng của họ, họ sẽ gửi yêu cầu sử dụng CPU tới hệ điều hành thông qua các thiết bị đầu cuối. Hệ điều hành thường sắp xếp các yêu cầu này theo tuần tự thời gian và đưa chúng vào một hàng đợi. Sau đó, CPU sẽ được cấp cho người dùng đầu hàng của hàng đợi để sử dụng. Khi chương trình tương ứng hoàn thành hoặc hết thời gian được cấp, nó sẽ rời khỏi hàng đợi và CPU sẽ được cấp cho người dùng tiếp theo trong hàng đợi. Điều này đảm bảo rằng các yêu cầu của người dùng được đáp ứng và CPU hoạt động một cách bình thường.
- Ngoài ra, hàng đợi còn được sử dụng trong các ứng dụng như bộ đệm vòng trong Linux, hàng đợi Disruptor có hiệu suất cao, GCD và NSOperationQueue trong iOS đều sử dụng cấu trúc hàng đợi.