Queue DS
Queue DS
In Deque or Double Ended Queue, insertion and deletion can be done from both ends
of the queue either from the front or rear.
It means that we can insert and delete elements from both front and rear ends of the
queue.
Deque can be used as a palindrome checker means that if we read the string from both
ends, then the string would be the same.
Deque can be used both as stack and queue as it allows the insertion and deletion
operations on both ends.
Deque can be considered as stack because stack follows the LIFO (Last In First Out)
principle in which insertion and deletion both can be performed only from one end. And
in deque, it is possible to perform both insertion and deletion from one end, and Deque
does not follow the FIFO principle.
To know more about the deque, you can click the link - https://www.javatpoint.com/ds-
deque
o Input restricted deque - As the name implies, in input restricted queue, insertion
operation can be performed at only one end, while deletion can be performed
from both ends.
o Enqueue: The Enqueue operation is used to insert the element at the rear end of the
queue. It returns void.
o Dequeue: It performs the deletion from the front-end of the queue. It also returns the
element which has been removed from the front-end. It returns an integer value.
o Peek: This is the third operation that returns the element, which is pointed by the front
pointer in the queue but does not delete it.
o Queue overflow (isfull): It shows the overflow condition when the queue is completely
full.
o Queue underflow (isempty): It shows the underflow condition when the Queue is
empty, i.e., no elements are in the Queue.
There are two variables i.e. front and rear, that are implemented in the case of every
queue. Front and rear variables point to the position from where insertions and
deletions are performed in a queue.
Initially, the value of front and queue is -1 which represents an empty queue.
Array representation of a queue containing 5 elements along with the respective values
of front and rear, is shown in the following figure.
The above figure shows the queue of characters forming the English word "HELLO".
Since, No deletion is performed in the queue till now,
However, the value of rear increases by one every time an insertion is performed in the
queue. After inserting an element into the queue shown in the above figure, the queue
will look something like following. The value of rear will become 5 while the value of
front remains same.
After deleting an element, the value of front will increase from -1 to 0. however, the
queue will look something like following.
Otherwise, keep increasing the value of front and return the item stored at the front end
of the queue at each time.
Drawback of array implementation
The technique of creating a queue is easy, but there are some drawbacks of using this
technique to implement a queue.
o Memory wastage : The space of the array, which is used to store queue elements, can
never be reused to store the elements of that queue because the elements can only be
inserted at front end and the value of front might be so high so that, all the space before
that, can never be filled.
A queue of size 10 having 3 elements, is shown. The value of the front variable is 5,
therefore, we can not reinsert the values in the place of already deleted element before
the position of front. That much space of the array is wasted and can not be used in the
future (for this queue).
On of the most common problem with array implementation is the size of the array
which requires to be declared in advance.
Due to the fact that, the queue can be extended at runtime depending upon the
problem, the extension in the array size is a time taking process and almost impossible
to be performed at runtime since a lot of reallocations take place.
Due to this reason, we can declare the array large enough so that we can store queue
elements as enough as possible but the main problem with this declaration is that, most
of the array slots (nearly half) can never be reused. It will again lead to memory wastage.
In a linked queue, each node of the queue consists of two parts i.e. data part and the
link part. Each element of the queue points to its immediate next element in the
memory.
In the linked queue, there are two pointers maintained in the memory i.e. front pointer
and rear pointer. The front pointer contains the address of the starting element of the
queue while the rear pointer contains the address of the last element of the queue.
Insertion and deletions are performed at rear and front end respectively. If front and
rear both are NULL, it indicates that the queue is empty.
Insert operation
The insert operation append the queue by adding an element to the end of the queue.
The new element will be the last element of the queue.
Firstly, allocate the memory for the new node ptr by using the following statement.
There can be the two scenario of inserting this new node ptr into the linked queue.
In the first scenario, we insert element into an empty queue. In this case, the
condition front = NULL becomes true.
Now, the new element will be added as the only element of the queue and the next
pointer of front and rear pointer both will point to NULL.
1. ptr -> data = item;
2. if(front == NULL)
3. {
4. front = ptr;
5. rear = ptr;
6. front -> next = NULL;
7. rear -> next = NULL;
8. }
The condition front = NULL becomes false. In this scenario, we need to update the end
pointer rear so that the next pointer of rear will point to the new node ptr.
Since, this is a linked queue, hence we also need to make the rear pointer point to the
newly added node ptr.
Deletion
Deletion operation removes the element that is first inserted among all the queue
elements.
Otherwise, we will delete the element that is pointed by the pointer front.
For this purpose, copy the node pointed by the front pointer into the pointer ptr.
Now, shift the front pointer, point to its next node and free the node pointed by the
node ptr. This is done by using the following statements.
1. ptr = front;
2. front = front -> next;
3. free(ptr);
If the rear reaches to the end position of the Queue then there might be possibility that
some vacant spaces are left in the beginning which cannot be utilized. So, to overcome
such limitations, the concept of the circular queue was introduced.
As we can see in the above image, the rear is at the last position of the Queue and front
is pointing somewhere rather than the 0 th position.
In the above array, there are only two elements and other three positions are empty. The
rear is at the last position of the Queue; if we try to insert the element then it will show
that there are no empty spaces in the Queue.
There is one solution to avoid such wastage of memory space by shifting both the
elements at the left and adjust the front and rear end accordingly.
It is not a practically good approach because shifting all the elements will consume lots
of time.
The efficient approach to avoid the wastage of the memory is to use the circular queue
data structure.
Enqueue operation
The steps of enqueue operation are given below:
o If rear != max - 1, then rear will be incremented to mod(maxsize) and the new
value will be inserted at the rear end of the queue.
o If front != 0 and rear = max - 1, it means that queue is not full, then set the
value of rear to 0 and insert the new element there.
o When front ==0 && rear = max-1, which means that front is at the first position
of the Queue and rear is at the last position of the Queue.
o front== rear + 1;
Dequeue Operation
The steps of dequeue operation are given below:
o First, we check whether the Queue is empty or not. If the queue is empty, we
cannot perform the dequeue operation.
o When the element is deleted, the value of front gets decremented by 1.
o If there is only one element left which is to be deleted, then the front and rear are
reset to -1.
Let's understand the enqueue and dequeue operation through the diagrammatic
representation.
What is a priority queue?
A priority queue is an abstract data type that behaves similarly to the normal queue
except that each element has some priority, i.e., the element with the highest priority
would come first in a priority queue.
The priority of the elements in a priority queue will determine the order in which
elements are removed from the priority queue.
The priority queue supports only comparable elements, which means that the elements
are either arranged in an ascending or descending order.
For example, suppose we have some values like 1, 3, 4, 8, 14, 22 inserted in a priority
queue with an ordering imposed on the values is from least to the greatest. Therefore,
the 1 number would be having the highest priority while 22 will be having the lowest
priority.
o Every element in a priority queue has some priority associated with it.
o An element with the higher priority will be deleted before the deletion of the
lesser priority.
o If two elements in a priority queue have the same priority, they will be arranged
using the FIFO principle.
1, 3, 4, 8, 14, 22
All the values are arranged in ascending order. Now, we will observe how the priority
queue will look after performing the following operations:
o poll(): This function will remove the highest priority element from the priority
queue. In the above priority queue, the '1' element has the highest priority, so it
will be removed from the priority queue.
o add(2): This function will insert '2' element in a priority queue. As 2 is the
smallest element among all the numbers so it will obtain the highest priority.
o poll(): It will remove '2' element from the priority queue as it has the highest
priority queue.
o add(5): It will insert 5 element after 4 as 5 is larger than 4 and lesser than 8, so it
will obtain the third highest priority in a priority queue.
We will create the priority queue by using the list given below in which INFO list
contains the data elements, PRN list contains the priority numbers of each data element
available in the INFO list, and LINK basically contains the address of the next node.
arrays,
linked list,
The heap data structure is the most efficient way of implementing the priority queue, so
we will implement the priority queue using a heap data structure.
Analysis of complexities using different implementations
What is Heap?
A heap is a tree-based data structure that forms a complete binary tree, and satisfies the
heap property. If A is a parent node of B, then A is ordered with respect to the node B
for all nodes A and B in a heap.
It means that the value of the parent node could be more than or equal to the value of
the child node,
or the value of the parent node could be less than or equal to the value of the child
node. Therefore, we can say that there are two types of heaps:
o Max heap: The max heap is a heap in which the value of the parent node is
greater than the value of the child nodes.
o Min heap: The min heap is a heap in which the value of the parent node is less
than the value of the child nodes.
Both the heaps are the binary heap, as each has exactly two child nodes.
If we insert an element in a priority queue, it will move to the empty slot by looking
from top to bottom and left to right.
If the element is not in a correct place then it is compared with the parent node; if it is
found out of order, elements are swapped. This process continues until the element is
placed in a correct position.
o Removing the minimum element from the priority queue
As we know that in a max heap, the maximum element is the root node. When we
remove the root node, it creates an empty slot. The last inserted element will be added
in this empty slot. Then, this element is compared with the child nodes, i.e., left-child
and right child, and swap with the smaller of the two. It keeps moving down the tree
until the heap property is restored.
Applications of Priority queue
The following are the applications of the priority queue: