You are on page 1of 16

www.itspiritclub.

net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT

Cấu trúc dữ liệu Queue (hàng đợi)

Mở đầu
Đặc điểm của cấu trúc dữ liệu hàng đợi là khi bổ sung được thực hiện vào cuối hay đuôi của hàng đợi
trong khi thao tác lấy ra được thực hiện từ phía trước hay đầu hàng đợi. Ngược lại với đặc điểm này của hàng
đợi đó là stack , một cấu trúc kiểu FIFO ( First–In First-Out - vào trước ra sau )

Sử dụng hàng đợi trong trường hợp tốc độ khách hàng yêu cầu các dịch vụ trong cùng thời điểm vượt
quá tốc độ mà khả năng các dịch vụ này cung ứng được. Ví dụ, trong một mạng chia sẻ có nhiều máy tính nhưng
chỉ có một vài máy in, công việc in ấn có thể gom lại vào một hàng đợi in. Trong một hệ điều hành với giao diện
đồ họa, các ứng dụng và cửa sổ giao tiếp bằng các thông điệp (message) được đặt trong một hàng đợi thông điệp
cho đến khi hệ điều hành có thể xử lí chúng.

Các thao tác


Add thêm vào một nút mới

Remove hủy bỏ một nút

Các hàm bổ sung

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

IsFull Kiểm tra hàng đợi có đầy

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

Destroy Hủy nội dung của hàng đợi ( có thể thực hiện điều này bằng cách tái khởi tạo hàng đợi )

1/ Initalise
Khởi tạo cấu trúc – đảm bảo rằng cấu trúc tồn tại mà không cần biết có chứa các thuộc tính hay không .

VD: Initalise(Q) tạo một hàng đợi rỗng đặt tên là Q

2/ Add
VD: Add(X,Q) thêm nút có giá trị X vào đuôi hàng đợi Q

Sau đó, Add(Y,Q) thêm nút có giá trị Y vào đuôi hàng đợi Q

1
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT

3/ Remove
VD: Remove(Q) Hủy nút đầu của hàng đợi Q và trả về giá trị của nút đó

Bảng ví dụ mẫu

Bài tập: Các thao tác hàng đợi


Hãy cho biết nội dung của hàng đợi sau khi thực hiện các thao tác sau ?

Initialise(Q)

Add(A,Q)

Add(F,Q)

Add(X,Q)

Remove(Q)

Add(B,Q)

Remove(Q)

Remove(Q).

2
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT

Lưu trữ một hàng đợi vào cấu trúc dữ liệu tĩnh

Thực hiện điều này bằng cách lưu hàng đợi vào một mảng. Các chỉ số mảng lưu trữ đuôi và đầu của hàng đợi
phải luôn được duy trì. Đầu của hàng đợi không nhất thiết lưu tại chỉ số 0. Mảng có thể là “mảng vòng ” –
tương ứng với hàng đợi “bọc quanh” nếu chỉ số cuối của mảng đạt tới - tức là đủ tạo được thành vòng.

Ví dụ: Lưu trữ một hàng đợi vào một mảng có 5 phần tử

3
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT

Bài tập: Hàng đợi được lưu vào cấu trúc dữ liệu tĩnh
Tiếp tục ví dụ trên. Hãy vẽ lại trạng thái của hàng đợi sau khi thực hiện các thao tác sau:

Add(E,Q)

Remove(Q)

Add(W,Q)

Add(J,Q)

Add(K,Q)

Lưu trữ một hàng đợi vào cấu trúc dữ liệu động

Trong trường hợp là stack, mỗi nút trong cấu trúc dữ liệu động chứa dữ liệu VÀ tham chiếu đến nút kế tiếp

Hàng đợi cũng cần một tham chiếu đến nút đầu VÀ một tham chiếu đến nút cuối

Hình vẽ dưới đây mô tả việc lưu trữ của một hàng đợi gọi là Queue. Mỗi nút bao gồm dữ liệu (DataItem) và một
tham chiếu (NextNode)

Truy cập nút đầu tiên bằng cách sử dụng tên Queue.Head

Truy cập đến dữ liệu của nó bằng cách sử dụng Queue.Head.DataItem

Truy cập đến nút thứ hai bằng cách sử dụng Queue.Head.NextNode

Truy cập đến nút cuối cùng bằng cách sử dụng Queue.Tail

Thêm một nút (Add)


Nút mới được thêm vào đuôi của hàng đợi. Tham chiếu Queue.Tail sẽ trỏ đến nút mới và tham chiếu NextNode
của nút trước đó của đuôi hàng đợi sẽ trỏ đến DataItem của nút mới.

4
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT

Hủy một nút (Remove)


Trả về giá trị của Queue.Head.DataItem. Một tham chiếu tạm thời Temp được khai báo và trỏ đến nút đầu hàng
đợi ( Temp = Queue.Head). Queue.Head sau đó được trỏ đến nút thứ hai thay vì nút đầu tiên. Lúc này tham
chiếu đến nút đầu giờ là Temp không sử dụng nữa có thể giải phóng nó khỏi bộ nhớ.

5
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT
Thực hiện hàng đợi
Các bộ sưu tập Java Framwork trong các phiên bản mới nhất của Java hiện nay bao gồm các lớp hàng đợi. Như
những gì bạn đã làm với stack, bạn sẽ tạo ra một lớp hàng đợi của riêng bạn để tìm hiểu cách thức một hàng đợi
làm việc. Lớp hàng đợi của bạn sẽ đơn giản hơn một chút so với các bộ sưu tập Framwork nhưng về cơ bản là
như nhau.

Lớp hàng đợi

Các nút của hàng đợi được biểu diễn bằng các thể hiện của lớp Node. Mỗi thể hiện của lớp Node lưu giữ một
mục dữ liệu (data item), loại đối tượng, và tham chiếu đến nút kế tiếp của nó. Mục dữ liệu có thể là một trong
bất kỳ loại đối tượng nào của Java

Lớp hàng đợi (Queue) có tham chiếu đến 2 nút, nút đầu và nút cuối. Hàm khởi tạo thiết lập các tham chiếu đó
đến NULL để khởi tạo một hàng đợi ban đầu rỗng.

Hàng đợi không có kích cỡ cố định, vì vậy nó sẽ không bao giờ đầy (trừ khi máy tính không còn đủ bộ nhớ ).
Phương thức isFull ở đây sẽ trả về False.

Node.java

/**

* class Node

* @author Jim

* @version 1.0
6
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT
*/

public class Node

Object dataItem;

Node nextNode;

Queue.java

/**
* class Queue
*
* @author Jim
* @version 1.0
*/
public class Queue
{
public Node head;
public Node tail;

/**
* Constructor for objects of class Queue
*/
public Queue()
{
// initialise head and tail references
head = null;
tail = null;
}
/**
* sets all queue entries to null
*
**/
public void destroy()
{
Node temp = new Node();
Node setNull = new Node();
temp = head;
while (temp!=null)
{
setNull = temp;
temp = temp.nextNode;
setNull = null;
}
head = null;
tail = null;
}

7
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT

/**
* checks whether queue is empty
*/
public boolean isEmpty()
{
return head == null;
}

/**
* checks whether queue is full - not properly
* implemented here
*/
public boolean isFull()
{
return false;
}
/**
* add an item to the queue
*/
public void add(Object o)
{
Node newNode = new Node();
newNode.dataItem = o;
if (tail == null)
{
head = newNode;
tail = newNode;
}
else
{
tail.nextNode = newNode;
tail = newNode;
}
}

/**
* remove an item by obeying FIFO rule
*/
public Object remove()
{
if (head == null)
return null;
else
{
Node temp = new Node();
temp = head;
head = head.nextNode;
if (head == null) tail = null;
return temp.dataItem;
}
}

8
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT

/**
* returns the number of items in the queue
*/
public int size()
{
int count = 0;
for (Node current=head;current!=null;current=current.nextNode)
count++;
return count;
}
}

Sử dụng một hàng đợi


Để sử dụng lớp Queue, bạn cần phải biết làm thế nào để viết code gọi các thao tác trên hàng đợi.

Hãy nhớ rằng hàng đợi có thể chứa bất kì loại dữ liệu nào. Lớp QueueTester sau đây cho thấy cách sử dụng một
hàng đợi để lưu giữ các đối tượng String. Phần gọi các thao tác hàng đợi được tô đậm

/**
* class QueueTester
*
* @author Jim
* @version 1.0
*/
public class QueueTester {
private Queue queue;

public QueueTester(){
queue = new Queue();
}
public QueueTester(Queue queue){
this.queue = queue;
}
/**
* add item to queue
*/
public void addString(String str) {
queue.add(str);
System.out.println("Added new string");
}
/**
* remove item from queue
*/
public void removeString() {
String result = (String) queue.remove();
if (result!=null)
System.out.println("String is :" + result);
else
System.out.println("Remove was unsuccessful");
}

9
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT
/**
* check if queue is empty
*/
public void checkIfEmpty() {
if (queue.isEmpty())
System.out.println("Queue empty");
else
System.out.println("Queue is not empty");
}
/**
* list the strings in queue
*/
public void listStringsInQueue() {
if (queue.isEmpty()) {
System.out.println("Queue empty");
}
else {
System.out.println("Strings in queue are: ");
System.out.println();
Node node = queue.head;
while (node != null){
String item = (String)node.dataItem;
System.out.println(item);
node = node.nextNode;
}
System.out.println();
}
}
}

Bài tập: Sử dụng hàng đợi


Tạo một project mới đặt tên là BlueJ, tạo các lớp Node, Queue và QueueTester bằng cách sử dụng các đoạn
code trên

Tạo một thể hiện mới của lớp Queue

Tạo một thể hiện mới của lớp QueueTester và chọn thể hiện của lớp Queue bạn vừa tạo làm tham số trong hàm
khởi tạo . Điều này nghĩa là bạn sẽ kiểm tra được hàng đợi bạn đã tạo trong bước trước

Gọi phương thức checkIfEmpty của lớp QueueTester

Kết quả là gì ?

Gọi phương thức AddString của lớp QueueTester để thêm chuỗi “The” vào hàng đợi. Tiếp tục dùng phương
thức này để thêm các chuỗi sau:

“queue”, “gets”, “longer”

Gọi phương thức removeString của lớp QueueTester và kiểm tra kết quả có chính xác ?

Gọi phương thức AddString của lớp QueueTester để thêm 2 chuỗi “every” và “day” vào hàng đợi
10
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT
Nội dung hàng đợi của bạn lúc này sẽ ra sao ?

Duyệt lại đối tượng hàng đợi của bạn. Bạn sẽ thấy tham chiếu đến đầu và đuôi của hàng đợi.

Kiểm tra tham chiếu đến đầu hàng đợi. Một đối đượng Inspector mới xuất hiện

Kiểu đối tượng của đầu hàng đợi là gì ?

DataItem của nó là gì ?

Click vào tham chiếu NextNode để chọn nó và click vào nút Inspect

Bạn thấy những gì ?

Đi qua từng nút của hàng đợi bằng cách sử dụng tham chiếu nextNode mỗi lần đi từ nút này đến nút kế tiếp

Bạn có thấy dữ liệu theo thứ tự bạn mong đợi ?

Bằng cách nào bạn biết mình đã đi đến nút cuối cùng ?

Có cách nào khác để nhận biết được nút cuối cùng hay không ?

11
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT
Hãy cố gắng hủy và thêm một vài nút nữa, kiểm tra lại nội dung hàng đợi sau khi bạn thực hiện mỗi thao tác

Bạn có thể theo dõi thông qua từng nút như trên hoặc bạn có thể gọi phương thức listStringsInQueue của lớp
QueueTester

Các nút mà bạn thêm vào sẽ ở đâu ?

Các nút mà bạn hủy đi sẽ ở đâu ?

Hàng đợi thay đổi như thế nào khi bạn hủy một nút ?

Chú ý: Chúng tôi chọn việc thực hiện hàng đợi này bằng cấu trúc động. Chúng ta có thể tạo một cấu trúc hàng
đợi tĩnh bằng cách sử dụng mảng. Phương thức thêm và hủy cũng sẽ có tác dụng tương tự. Tuy nhiên , cách thức
mà dữ liệu thực sự được lưu trữ sẽ tương tự như cấu trúc dữ liệu tĩnh bạn đã tìm hiểu trong chương ngăn xếp.

Bài tập: Lưu trữ kiểu dữ liệu khác

Sửa lớp QueueTester lưu các đối tượng Double trong hàng đợi thay vì các đối tượng String, kiểm tra lại kết quả
theo các bước tương tự như trên

Bài tập: Một ứng dụng thực tế của lớp hàng đợi
Hàng đợi là một cấu trúc dữ liệu hữu ích để lưu trữ dữ liệu cần xử lí theo trình tự nó được tạo ra, nhưng có thể
không phải lúc nào cũng được xử lí ngay. Một ứng dụng điển hình của hàng đợi đó là hệ thống nhắn tin. Trong
ví dụ sau đây, thông điệp nhận được theo thứ tự chúng được gửi đi

Các lớp liên quan là Message, MessageSender và MessageReceiver:

+ Một đối tượng Message có một người gửi, một người nhận, một chuỗi nội dung và ngày tháng

+ Một đối tượng Message được đặt trong một hàng đợi bởi một đối tượng MessageSender

+ Một Message được lấy ra khỏi hàng đợi bởi một đối tượng MessageReceiver có thể hiển thị nội dung của hàng
đợi

Lớp hàng đợi bạn tạo ra chong chương này có thể chứa bất kì loại đối tượng nào , kể cả đối tượng Message, vì
vậy bạn có thể sử dụng nó trong bài tập này

Thêm các lớp sau đây vào project hàng đợi của bạn

12
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT
Message.java

import java.text.*;
import java.util.Date;

/**
* class Message
*
* @author Jim
* @version 1.0
*/
public class Message
{
public String sender;
public String recipient;
public String content;
public Date date;
/**
* Constructors for objects of class Message
*/
public Message()
{
this.sender = "unknown sender";
this.recipient = "unknown recipient";
this.content = "none";
this.date = new Date();
}

public Message(String sender, String recipient, String content)


{
this.sender = sender;
this.recipient = recipient;
this.content = content;
this.date = new Date();
}

/**
* returns date/time at which message was created
*
* @return String - formatted representation of date
**/
public String getDate()
{
returnDateFormat.getDateTimeInstance();
format(this.date);
}
}

13
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT

MessageSender.java

/**

* class MessageSender

* @author Jim

* @version 1.0

*/
public class MessageSender
{

/**
* places a message on a specified queue
*
*/
public void sendMessage(String sender, String recipient,String content,
Queue q)
{
Message m = new Message(sender, recipient, content);
if(!q.isFull())
{
q.add(m);
System.out.println("Message placed on queue");
}
else
System.out.println("Cannot send - queue is full");
}
}

MessageReceiver.java

14
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT
*/
public class MessageReceiver
{

/**
* receives and outputs a message from a specified queue
*
*/
public void receiveMessage(Queue q)
{
Message m = (Message) q.remove();
if (m != null)
{
System.out.println("Date: " + m.getDate());
System.out.println("From: " + m.sender);
System.out.println("To: " + m.recipient);
System.out.println("Content: " + m.content);
}
else
System.out.println("No messages to receive");
}

/**
* outputs contents of a queue
*
*/
public void showQueue(Queue q)
{
Message m;
System.out.println("Queue contains " + q.size() + " messages");

/**

* class MessageReceiver

* @author Jim

* @version 1.0

15
www.itspiritclub.net Cấu trúc dữ liệu Queue Translater: Group ITSPIRIT

if (q.isEmpty()) {
System.out.println("Queue empty");
}
else {
Node node = q.head;
while (node != null){
m = (Message)node.dataItem;
System.out.println(m.getDate() + ", From:" + m.sender + ",
To:" + m.recipient);
node = node.nextNode;
}
}
}
}
Bây giờ bạn cho chạy kiểm tra theo trình tự sau đây:

1. Tạo các thể hiện của lớp MessageSender, MessageReceiver và lớp hàng đợi của bạn.
2. Sử dụng thể hiện của lớp MessageSender để thêm các tin nhắn sau vào hàng đợi:
Sender Recipient Content
Bob Alice Hello
Jane Joe Good Morning
Jack Jill See you later
3. Sử dụng các thể hiện của lớp MessageReceiver để :
+ Hiển thị các nội dung hàng đợi
+ Hủy tin nhắn đầu tiên trong hàng đợi
+ Hiển thị các nội dung hàng đợi một lần nữa
4. Sử dụng các phương thức thích hợp để thêm các tin nhắn sau vào hàng đợi, hủy tin nhắn đầu
tiên và hiển thị các nội dung hàng đợi lần nữa
Sender Recipient Content
George Mildred Good Evening
Diane Sam Bye for now
5. Sử dụng các phương thức thích hợp để hủy tin nhắn đầu tiên và thêm các tin nhắn sau vào hàng
đợi, hiển thị các nội dung hàng đợi lần nữa

16

You might also like