You are on page 1of 20

QUEUE

It is an ordered list in which insertions are done at one end (rear) and deletions are done at the other end (front). First element to be inserted is first one to be removed. Hence it is called FIFO or LILO list. Similar to stack special names are given to two changes that can be made to a queue. When an element is inserted then the concept is called ENQUEUE and when an element is deleted then the concept is called DEQUEUE. Trying to DEQueue an empty queue is called underflow and trying to Enqueue an element in full queue is called overflow. Generally we treat them as exceptions.

Elements ready to be served (DeQueue) Front Rear

New Elements ready to enter Queue (EnQueue)

QUEUE As ADT
Main queue operations :
EnQueue (int data) : Inserts at the end of the Queue Int DeQueue() :Removes and returns the element at the front of the queue Auxillary Queue Operations
Int Front() : returns the element at the front without removing it. Int QueueSize() : Returns the number of elements stored. Int IsEmptyQueue() : indicates whether no elements are stored.

Applications
Direct Applications
Operating systems schedule jobs with equal priority in order of arrival
Simulation of real world queues such as lines at a ticket counter. Multiprogramming Asynchronous data transfer (file IO , pipes , sockets) Waiting time of customers at call centres

InDirect Applications
Auxiliary data structure for algorithms Components of other data structure

Circular Arrays
Neat trick: use a circular array to insert and remove items from a queue in constant time The idea of a circular array is that the end of the 7 array wraps around to the start of 0 the array
6 1

5 4 3

The mod Operator


The mod operator (%) is used to calculate remainders:
1%5 = 1, 2%5 = 2, 5%5 = 0, 8%5 = 3

mod can be used to calculate the front and back positions in a circular array, therefore avoiding comparisons to the array size
The back of the queue is:
(front + count - 1) % items.length where count is the number of items currently in the queue

After removing an item the front of the queue is:


(front + 1) % items.length;

Array Queue Example


front =
count = 6
0 1 2 3 4 5

0
1 0

insert item at (front + count) % items.length

Array Queue Example


front =
count = 6
0

0
5 4 3 2 1 7
2

4
1

3
3

8
4 5

Array Queue Example


front =
count = 6
0

1 2 0
3 4 5 7
2

4
1

3
3

8
4

9
5

make front = (0 + 1) % 6 = 1 make front = (1 + 1) % 6 = 2

Array Queue Example


front =
count = 5
0 1

2
5 4 7
2

3
3

8
4

9
5

insert at (front + count) % 6 = (2 + 4) % 6 = 0

Implementation
Implementing queue operations :
Simple circular array based implementation
Dynamic circular array based implementation Linked list implementation

Why circular arrays :


We know in queues insertions are performed at one end and deletions on the other end. After some insertions and deletions it is easy to get the situation as below :

Front

Rear

New elements ready to enter Queue (enqueue)

So from the diagram we can see that initial slots of array are getting wasted , so simple array implementation for queue is not efficient. To solve the problem we assume the arrays as circular arrays, i.e. we treat last and first element are contiguous. So in this way if there are any free slots at the beginning , the rear pointer can easily go to its next free slot.

Fixed size array


Rear

Front

Use two variables to keep track of start and end element. Front indicating start element and rear indicating the last element. Initially both pointing to -1 which indicates the queue is empty. Struct Arrayqueue { int front,rear; int capacity; int *array;

};
Struct Arrayqueue *Queue(int size) { struct Arrayqueue *Q=malloc(sizeof(struct Arrayqueue)); if(!Q) return NULL;

Q->capacity=size;
Q->front= Q->rear=-1; Q->array=malloc(Q->capacity *sizeof(int)); if(! Q->array)

return NULL;
return Q; }

Int IsEmptyqueue(struct Arrayqueue *Q){


return(Q->front== -1); } Int isfullqueue(struct Arrayqueue *Q) { return((Q->rear+1)%Q->capacity ==Q->front); }

Int queuesize() {
return(Q->capacity - Q->front + Q->rear +1)%Q->capacity } Void Enqueue(struct Arrayqueue *Q, int data)

if(isfullqueue(Q))
printf(queue overflow); else {Q->rear=(Q->rear +1)%Q->capacity Q->array[Q->rear]=data; if(Q->front== -1) Q->front = Q->rear; }

Some questions: 1. give an algorithm for reversing a queue Q. to access the queue we are only allowed to use methods of queue ADT

void reversequeue(struct Queue *Q) {


struct Stack * S = CreateStack(); while(!isemptyqueue(Q)) push(S,Dequeue(Q)) while(!isemptystack(S)) EnQueue(Q,Pop(S)); }

Dequeue
DeQueue is a data structure in which elements may be added to or deleted from the front or the rear. The DeQueue is represented as follows.

Multi stack & queue


Multiple Stacks:
Following pictures are two ways to do two stacks in array: None fixed size of the stacks:
Stack 1 expands from the 0th element to the right

Stack 2 expands from the 12th element to the left


As long as the value of Top1 and Top2 are not next to each other, it has free elements for input the data in the array When both Stacks are full, Top1 and Top 2 will be next to each other There is no fixed boundary between Stack 1 and Stack 2

Fixed size of the stacks:


Stack 1 expands from the 0th element to the right Stack 2 expands from the 6th element to the left As long as the value of Top 1 is less than 6 and greater than 0, Stack 1 has free elements to input the data in the array

As long as the value of Top 2 is less than 11 and greater than 5, Stack 2 has free elements to input the data in the array
When the value of Top 1 is 5, Stack 1 is full When the value of Top 2 is 10, stack 2 is full

Multiple Queues:

Following pictures are two ways to do two queues in array:


None fixed size of the queues: Queue 1 expands from the 0th element to the right and circular back to the 0thelement Queue 2 expands from the 8th element to the left and circular back to the 8thelement Temporary boundary between the Queue 1 and the Queue 2; as long as there has free elements in the array and boundary would be shift Free elements could be any where in the Queue such as before the front, after the rear, and between front and rear in the Queue Queue 1s and Queue 2 s size could be change if it is necessary. When the Queue 1 is full and the Queue 2 has free space; the Queue 1 can increase the size to use that free space from the Queue 2. Same way for the Queue 2 Elements 1, 2, and 3 are using to store the size of the Queue 1, the front of the Queue 1, and the data count for the Queue 1 needed to manipulate the Queue 1 Elements 4, 5, and 6 are using to store the size of the Queue 2, the front of the Queue 2, and the data count for the Queue 2 needed to manipulate the Queue 2 Inserts data to the Queue 1, Q1Rear = (Q1Front + Q1count) % Q1Size Inserts data to the Queue 2, Q2Rear = (Q2Front + Q2count) % Q2Size + Q1Size Deletes data from the Queue 1, Q1Front = (Q1Front + 1) % Q1Size Deletes data from the Queue 2, Q2Front = (Q2Front + 1) % Q2Size + Q1Size

Fixed size of the queue: Queue 1 expands from the 0th element to the 4th element and circular back to 0thelement Queue 2 expands from the 8th element to the 5th element and circular back to 8thelement The boundary is fixed between the Queue 1 and the Queue 2 Free elements could be any where in the Queue such as before the front, after the rear, and between front and rear in the Queue

Elements 1, 2, and 3 are using to store the size of the Queue 1, the front of the Queue 1, and the data count for the Queue 1 needed to manipulate the Queue 1
Elements 4, 5, and 6 are using to store the size of the Queue 2, the front of the Queue 2, and the data count for the Queue 2 needed to manipulate the Queue 2

Inserts data to the Queue 1, Q1Rear = (Q1Front + Q1count) % Q1Size


Inserts data to the Queue 2, Q2Rear = (Q2Front + Q2count) % Q2Size + Q1Size Deletes data from the Queue 1, Q1Front = (Q1Front + 1) % Q1Size Deletes data from the Queue 2, Q2Front = (Q2Front + 1) % Q2Size + Q1Size

You might also like