Objectives Introduction Circular Queue

J.E.D.I 3 Queues

3.1 Objectives

At the end of the lesson, the student should be able to: • Define the basic concepts and operations on the ADT queue • Implement the ADT queue using sequential and linked representation • Perform operations on circular queue • Use topological sorting in producing an order of elements satisfying a given partial order

3.2 Introduction

A queue is a linearly ordered set of elements that has the discipline of First-In, First-Out. Hence, it is also known as a FIFO list. There are two basic operations in queues: 1 insertion at the rear, and 2 deletion at the front. To define the ADT queue in Java, we have the following interface: interface Queue{ Insert an item void enqueueObject item throws QueueException; Delete an item Object dequeue throws QueueException; } Just like in stack, we will make use of the following exception: class QueueException extends RuntimeException{ public QueueExceptionString err{ supererr; } }

3.3 Representation of Queues

Just like stack, queue may also be implemented using sequential representation or linked allocation. Data Structures 40 J.E.D.I

3.3.1 Sequential Representation

If the implementation uses sequential representation, a one-dimensional arrayvector is used, hence the size is static. The queue is empty if the front = rear and full if front=0 and rear=n. If the queue has data, front points to the actual front, while rear points to the cell after the actual rear. Deletion from an empty queue causes an underflow while insertion onto a full queue causes an overflow. The following figure shows an example of the ADT queue: Figure 1.15 Operations on a Queue Figure 1.16 To initialize, we set front and rear to 0: front = 0; rear = 0; To insert an item, say x, we do the following: Q[rear] = item; rear++; and to delete an item, we do the following: x = Q[front]; front++; To implement a queue using sequential representation: class SequentialQueue implements Queue{ Object Q[]; int n = 100 ; size of the queue, default 100 int front = 0; front and rear set to 0 initially int rear = 0; Create a queue of default size 100 SequentialQueue1{ Q = new Object[n]; } Create a queue of the given size SequentialQueue1int size{ n = size; Data Structures 41 J.E.D.I Q = new Object[n]; } Inserts an item onto the queue public void enqueueObject item throws QueueException{ if rear == n throw new QueueException Inserting into a full queue.; Q[rear] = item; rear++; } Deletes an item from the queue public Object dequeue throws QueueException{ if front == rear throw new QueueException Deleting from an empty queue.; Object x = Q[front]; front++; return x; } } Whenever deletion is made, there is space vacated at the “front-side” of the queue. Hence, there is a need to move the items to make room at the “rear-side” for future insertion. The method moveQueue implements this procedure. This could be invoked when void moveQueue throws QueueException{ if front==0 throw new QueueExceptionInserting into a full queue; forint i=front; in; i++ Q[i-front] = Q[i]; rear = rear - front; front = 0; } There is a need to modify the implementation of enqueue to make use of moveQueue: public void enqueueObject item{ if rear is at the end of the array if rear == n moveQueue; Q[rear] = item; rear++; }

3.3.2 Linked Representation

Linked allocation may also be used to represent a queue. It also makes use of nodes with fields INFO and LINK. The following figure shows a queue implemented as a linked list: Figure 1.17 Linked Representation of a Queue Data Structures 42 J.E.D.I The node definition in chapter 1 will also be used here. The queue is empty if front = null. In linked representation, since the queue grows dynamically, overflow will happen only when the program runs out of memory and dealing with that is beyond the scope of this topic. The following Java code implements the linked representation of the ADT queue: class LinkedQueue implements Queue{ queueNode front, rear; Create an empty queue LinkedQueue{ } Create a queue with node n initially LinkedQueuequeueNode n{ front = n; rear = n; } Inserts an item onto the queue public void enqueueObject item{ queueNode n = new queueNodeitem, null; if front == null { front = n; rear = n; } else{ rear.link = n; rear = n; } } Deletes an item from the queue public Object dequeue throws QueueException{ Object x; if front == null throw new QueueException Deleting from an empty queue.; x = front.info; front = front.link; return x; } }

3.4 Circular Queue

A disadvantage of the previous sequential implementation is the need to move the elements, in the case of rear = n and front 0, to make room for insertion. If queues are viewed as circular instead, there will be no need to perform such move. In a circular queue, the cells are considered arranged in a circle. The front points to the actual element at the front of the queue while the rear points to the cell on the right of the actual rear element clockwise. The following figure shows a circular queue: Data Structures 43 J.E.D.I Figure 1.18 Circular Queue Figure 1.19 To initialize a circular queue: front = 0; rear = 0; To insert an item, say x: Q[rear] = x; rear = rear + 1 mod n; To delete: x = Q[front]; front = front + 1 mod n; We use the modulo function instead of performing an if test in incrementing rear and front. As insertions and deletions are done, the queue moves in a clockwise direction. If front catches up with rear, i.e., if front = rear, then we get an empty queue. If rear catches up with front, a condition also indicated by front = rear, then all cells are in use and we get a full queue. In order to avoid having the same relation signify two different conditions, we will not allow rear to catch up with front by considering the queue as full when exactly one free cell remains. Thus a full queue is indicated by: front == rear + 1 mod n The following methods are implementations of inserting into and deleting from a circular queue: Data Structures 44 J.E.D.I public void enqueueObject item throws QueueException{ if front == rear n + 1 throw new QueueException Inserting into a full queue.; Q[rear] = item; rear = rear n + 1; } public Object dequeue throws QueueException{ Object x; if front == rear throw new QueueException Deleting from an empty queue.; x = Q[front]; front = front n + 1; return x; }

3.5 Application: Topological Sorting