Ch-3-Queue
Ch-3-Queue
The Queue
INTRODUCTION
Queue is an ordered list of items in which an item is inserted from one end called REAR of the
queue and deleted from another end called FRONT of the queue.
• Queue is a linear data structure.
• Front points to the beginning of the queue and Rear points to the end of the queue.
• Queue follows the FIFO (First - In - First Out) structure.
• According to its FIFO structure, element inserted first will also be removed first.
• In a queue, one end is always used to insert data (enqueue) and the other is used to delete data
(dequeue), because queue is open at its both ends.
• The enqueue() and dequeue() are two basic functions used in a queue.
In a real-world analogy, we can imagine a bus queue where the passengers wait for the bus in a
queue or a line. The first passenger in the line enters the bus first as that passenger happens to be
the one who had come first.
Enqueue Operation
1
Else, add an element to the location pointed by ‘rear’.
Increment ‘rear’.
Return success.
Dequeue Operation
QUEUE AS AN ADT
template <class KeyType>
class Queue
{
//objects: a finite ordered list with zero or more elements.
public:
Queue(int MaxQueueSize=DefaultSize);
//create an empty queue whose maximum size is MaxQueueSize
Boolean IsFullQ();
//if (number of elements in queue== MaxQueueSize) return TRUE
//else return FALSE
Boolean IsEmptyQ();
//if number of elements in the queue is equal to 0 then return TRUE
//else return FALSE
Keytype* Delete(KeyType&);
//if (IsEmpty()) then QueueEmpty() and return 0
//else remove the item at front of queue and return a pointer to it.
~Queue() {}
};
2
APPLICATIONS OF QUEUE
Queue, as the name suggests is used whenever we need to manage any group of objects in an
order in which the first one coming in, also gets out first while the others wait for their turn, like
in the following scenarios:
1. Serving requests on a single shared resource, like a printer, CPU task scheduling etc.
2. In real life scenario, Call Center phone systems uses Queues to hold people calling them in
an order, until a service representative is free.
3. Handling of interrupts in real-time systems. The interrupts are handled in the same order
as they arrive i.e First come first served.
3
When we remove an element from Queue, we can follow two possible approaches (mentioned
[A] and [B] in above diagram). In [A] approach, we remove the element at head position, and then
one by one shift all the other elements in forward position.
In approach [B] we remove the element from head position and then move head to the next
position.
In approach [A] there is an overhead of shifting the elements one position forward every time we
remove the first element.
In approach [B] there is no such overhead, but whenever we move head one position ahead, after
removal of first element, the size on Queue is reduced by one space each time.
#include<iostream>
4
#define SIZE 10
class Queue
{
int a[SIZE];
int rear; //same as tail
int front; //same as head
public:
Queue()
{
rear = front = -1;
}
5
void Queue :: display()
{
int i;
for( i = front; i <= rear; i++)
{
cout << a[i] << endl;
}
}
q.display();
return 0;
}
To implement approach [A], you simply need to change the dequeue method, and include a for
loop which will shift all the remaining elements by one position.
The linear queue suffers from serious drawback after performing some operations, we cannot
insert items into queue, even if there is space in the queue. Suppose we have queue of 5 elements
6
and we insert 5 items into queue, and then delete some items, then queue has space, but at that
condition we cannot insert items into queue.
7
C++ program to implement a Linear queue using an array
#include <iostream>
using namespace std;
struct Queue {
int front, rear, capacity;
int* queue;
Queue(int c)
{
front = rear = 0;
capacity = c;
queue = new int;
}
8
for (int i = 0; i < rear - 1; i++) {
queue[i] = queue[i + 1];
}
// decrement rear
rear--;
}
return;
}
int main(void)
{
// Create a queue of capacity 4
Queue q(4);
9
q.queueEnqueue(30);
q.queueEnqueue(40);
q.queueEnqueue(50);
q.queueDequeue();
q.queueDequeue();
return 0;
}
10
In a normal Queue, we can insert elements until queue becomes full. But once queue becomes
full, we cannot insert the next element even if there is a space in front of queue.
11
3. Check if (front==rear) if it is true then set front=rear= -1 else check if (front==size-1),
if it is true then set front=0 and return the element.
#include<iostream>
#define SIZE 10
class CircularQueue
{
int a[SIZE];
int rear; //same as tail
int front; //same as head
public:
CircularQueue()
{
rear = front = -1;
}
// function to check if queue is full
bool isFull()
{
if(front == 0 && rear == SIZE - 1)
{
return true;
}
if(front == rear + 1)
{
return true;
}
return false;
}
12
}
}
if(isEmpty())
{
cout << "Queue is empty" << endl;
}
else
{
y = a[front];
if(front == rear)
{
// only one element in queue, reset queue after removal
front = -1;
rear = -1;
13
}
else
{
front = (front+1) % SIZE;
}
return(y);
}
}
14
cq.enqueue(1000);
cq.display();
return 0;
}
Time Complexity:
Time complexity of enQueue(), deQueue() operation is O(1) as there is no loop in any of the
operation.
Applications:
1. Memory Management: The unused memory locations in the case of ordinary queues can be
utilized in circular queues.
2. Traffic system: In computer controlled traffic system, circular queues are used to switch on
the traffic lights one by one repeatedly as per the time set.
3. CPU Scheduling: Operating systems often maintain a queue of processes that are ready to
execute or that are waiting for a particular event to occur.
Dequeue Operation
15
KeyType* Queue<KeyType>::Delete(KeyType &x)
//Remove front element from queue
{
if (front== rear) { QueueEmpty(); return 0;}
front= (front+ 1) % MaxSize;
x = queue[front];
return &x;
}
16
}
// Function to remove
// a key from given queue q
QNode* deQueue(Queue* q)
{
// If queue is empty, return NULL.
if (q->front == NULL)
return NULL;
q->front = q->front->next;
// Driver code
int main()
{
Queue* q = createQueue();
enQueue(q, 10);
17
enQueue(q, 20);
deQueue(q);
deQueue(q);
enQueue(q, 30);
enQueue(q, 40);
enQueue(q, 50);
QNode* n = deQueue(q);
if (n != NULL)
cout << "Dequeued item is " << n->key;
return 0;
}
Output:
Dequeued item is 30
Time Complexity:
Time complexity of both operations enqueue() and dequeue() is O(1) as we only change few
pointers in both operations. There is no loop in any of the operations.
TYPES OF QUEUE
Queue are of following types:
1. Linear queue
2. Circular queue
3. Priority queue
4. Dequeue (Double Ended Queue)
PRIORITY QUEUE
Priority Queue is an extension of queue with following properties.
1. Every item has a priority associated with it.
2. An element with high priority is dequeued before an element with low priority.
3. If two elements have the same priority, they are served according to their order in the
queue.
A priority queue is a special type of queue in which each element is associated with a priority and
is served according to its priority. If elements with the same priority occur, they are served
according to their order in the queue.
Generally, the value of the element itself is considered for assigning the priority. For example: The
element with the highest value is considered as the highest priority element. However, in other
case, we can assume the element with the lowest value as the highest priority element. In other
cases, we can set priority according to our need.
18
Implementation of Priority Queue
Priority queue can be implemented using an array, a linked list, a heap data structure or a binary
search tree. Among these data structures, heap data structure provides an efficient
implementation of priority queues.
Basic operations of a priority queue are inserting, removing and peeking elements.
Inserting an element into a priority queue (max heap) is done by following steps.
1. Insert the new element at the end of the tree.
19
2. Swap it with the last element.
20
DOUBLE ENDED QUEUE (DEQUE)
Double Ended Queue is also a Queue data structure in which the insertion and deletion operations
are performed at both the ends (front and rear). That means, we can insert at both front and rear
positions and can delete from both front and rear positions.
Double Ended Queue can be represented in TWO ways, those are as follows...
1. Input Restricted Double Ended Queue
2. Output Restricted Double Ended Queue
In input restricted double-ended queue, the insertion operation is performed at only one end and
deletion operation is performed at both the ends.
In output restricted double ended queue, the deletion operation is performed at only one end and
insertion operation is performed at both the ends.
Here we will implement a double ended queue using a circular array. It will have the following
methods:
1. push_back : inserts element at back
2. push_front : inserts element at front
21
3. pop_back : removes last element
4. pop_front : removes first element
5. get_back : returns last element
6. get_front : returns first element
7. empty : returns true if queue is empty
8. full : returns true if queue is full
Deque ADT
#define SIZE 5
class Dequeue
{
//front and rear to store the head and tail pointers
int *arr;
int front, rear;
public :
Dequeue()
{
//Create the array
arr = new int[SIZE];
// Operations on Deque
void push_front(int );
void push_back(int );
void pop_front();
void pop_back();
int get_front();
int get_back();
bool full();
bool empty();
};
Implementation of Deque
Insertion at front
void Dequeue :: push_front(int key)
{
if(full())
22
{
cout << "OVERFLOW\n";
}
else
{
//If queue is empty
if(front == -1)
front = rear = 0;
else
--front;
arr[front] = key;
}
}
Insertion at back
void Dequeue :: push_back(int key)
{
if(full())
{
cout << "OVERFLOW\n";
}
else
{
//If queue is empty
if(front == -1)
front = rear = 0;
else
++rear;
arr[rear] = key;
}
}
Delete from front (Delete first element)
void Dequeue :: pop_front()
{
if(empty())
{
cout << "UNDERFLOW\n";
}
else
{
23
//If only one element is present
if(front == rear)
front = rear = -1;
else
++front;
}
}
Delete from back (Delete last element)
void Dequeue :: pop_back()
{
if(empty())
{
cout << "UNDERFLOW\n";
}
else
{
//If only one element is present
if(front == rear)
front = rear = -1;
else
--rear;
}
}
Check if deque is empty
bool Dequeue :: empty()
{
if(front == -1)
return true;
else
return false;
}
Check if deque is full
bool Dequeue :: full()
{
if((front == 0 && rear == SIZE-1) ||(front == rear + 1))
return true;
else
return false;
}
24