DSA UNIT 2 (1)
DSA UNIT 2 (1)
STACK ADT
For example –
Infix notation: (A-B)*[C/(D+E)+F]
Here, we first perform the arithmetic inside the parentheses (A-B) and
(D+E). The division of C/(D+E) must be done prior to the addition with
F. After that multiply the two terms inside the parentheses and bracket.
Result: 60
2nd Step: Here i = 1 and exp[i] = ‘+’ i.e., an operator. Push this into the
stack. postfix = “a” and stack = {+}.
3rd Step: Now i = 2 and exp[i] = ‘b’ i.e., an operand. So add this in the
postfix expression. postfix = “ab” and stack = {+}.
4th Step: Now i = 3 and exp[i] = ‘*’ i.e., an operator. Push this into the
stack. postfix = “ab” and stack = {+, *}.
5th Step: Now i = 4 and exp[i] = ‘c’ i.e., an operand. Add this in the
postfix expression. postfix = “abc” and stack = {+, *}.
6th Step: Now i = 5 and exp[i] = ‘+’ i.e., an operator. The topmost
element of the stack has higher precedence. So pop until the stack
becomes empty or the top element has less precedence. ‘*’ is popped
and added in postfix. So postfix = “abc*” and stack = {+}.
Now top element is ‘+‘ that also doesn’t have less precedence. Pop
it. postfix = “abc*+”.
Now stack is empty. So push ‘+’ in the stack. stack = {+}.
7th Step: Now i = 6 and exp[i] = ‘d’ i.e., an operand. Add this in the
postfix expression. postfix = “abc*+d”.
Final Step: Now no element is left. So empty the stack and add it in the
postfix expression. postfix = “abc*+d+”.
QUEUE ADT
A Queue Data Structure is a fundamental concept in computer
science used for storing and managing data in a specific order. It
follows the principle of “First in, First out” (FIFO), where the first
element added to the queue is the first one to be removed. Queues are
commonly used in various algorithms and applications for their
simplicity and efficiency in managing data flow.
Representation of Queues
Similar to the stack ADT, a queue ADT can also be implemented using
arrays, linked lists, or pointers. As a small example in this tutorial, we
implement queues using a one-dimensional array.
Basic Operations in Queue
Queue uses two pointers − front and rear. The front pointer accesses
the data from the front end (helping in enqueueing) while the rear pointer
accesses data from the rear end (helping in dequeuing).
Algorithm
1. START
2. Check if the queue is full.
3. If the queue is full, produce overflow error and exit.
4. If the queue is not full, increment rear pointer to point
the next empty space.
5. Add data element to the queue location, where the rear
is pointing.
6. return success.
7. END
Algorithm
1. START
2. Check if the queue is empty.
3. If the queue is empty, produce underflow error and exit.
4. If the queue is not empty, access the data where front
is pointing.
5. Increment front pointer to point to the next available
data element.
6. Return success.
7. END
Algorithm
1. START
2. Return the element at the front of the queue
3. END
Algorithm
1. START
2. If the count of queue elements equals the queue size,
return true
3. Otherwise, return false
4. END
Queue - The isEmpty() operation
Algorithm
1. START
2. If the count of queue elements equals zero, return true
3. Otherwise, return false
4. END
Implementation of Queue:
• Sequential allocation: A queue can be implemented using
an array. It can organize a limited number of elements.
• Linked list allocation: A queue can be implemented
using a linked list. It can organize an unlimited number of
elements.
Advantages of Queue:
• A large amount of data can be managed efficiently with ease.
• Operations such as insertion and deletion can be performed
with ease as it follows the first in first out rule.
• Queues are useful when a particular service is used by
multiple consumers.
• Queues are fast in speed for data inter-process
communication.
• Queues can be used in the implementation of other data
structures.
Disadvantages of Queue:
• The operations such as insertion and deletion of elements from
the middle are time consuming.
• In a classical queue, a new element can only be inserted when
the existing elements are deleted from the queue.
• Searching an element takes O(N) time.
• Maximum size of a queue must be defined prior in case of
array implementation.
Applications of Queue
• Task scheduling in operating systems
• Data transfer in network communication
• Simulation of real-world systems (e.g., waiting lines)
• Priority queues for event processing queues for event
processing
CIRCULAR QUEUE
What is a Circular Queue?
A Circular Queue is an extended version of a normal queue where the
last element of the queue is connected to the first element of the queue
forming a circle.
The operations are performed based on FIFO (First In First Out)
principle. It is also called ‘Ring Buffer’.
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.
• Array
• Linked List
Here we have shown the implementation of a circular queue using an
array data structure.
Implement Circular Queue using Array:
1. Initialize an array queue of size n, where n is the maximum
number of elements that the queue can hold.
2. Initialize two variables front and rear to -1.
3. Enqueue: To enqueue an element x into the queue, do the
following:
• Increment rear by 1.
o If rear is equal to n, set rear to 0.
• If front is -1, set front to 0.
• Set queue[rear] to x.
4. Dequeue: To dequeue an element from the queue, do the
following:
• Check if the queue is empty by checking if front is -1.
o If it is, return an error message
indicating that the queue is empty.
• Set x to queue[front].
• If front is equal to rear, set front and rear to -1.
• Otherwise, increment front by 1 and if front is equal
to n, set front to 0.
• Return x.
#include<bits/stdc++.h>
using namespace std;
class Queue
{
// Initialize front and rear
int rear, front;
// Circular Queue
int size;
int *arr;
public:
Queue(int s)
{
front = rear = -1;
size = s;
arr = new int[s];
}
else
{
rear++;
arr[rear] = value;
}
}
return data;
}
q.displayQueue();
q.enQueue(9);
q.enQueue(20);
q.enQueue(5);
q.displayQueue();
q.enQueue(20);
return 0;
}
Output
Elements in Circular Queue are: 14 22 13 -6
Deleted value = 14
Deleted value = 22
Elements in Circular Queue are: 13 -6
Queue is Full
PRIORITY QUEUE
What is Priority Queue
A priority queue is a type of queue that arranges elements based on
their priority values. Elements with higher priority values are typically
retrieved before elements with lower priority values.
In a priority queue, each element has a priority value associated with it.
When you add an element to the queue, it is inserted in a position
based on its priority value. For example, if you add an element with a
high priority value to a priority queue, it may be inserted near the front
of the queue, while an element with a low priority value may be inserted
near the back.
Priority queues are often used in real-time systems, where the order in
which elements are processed can have significant consequences.
They are also used in algorithms to improve their efficiencies, such
as Dijkstra’s algorithm for finding the shortest path in a graph and the
A* search algorithm for pathfinding.
Properties of Priority Queue
So, a priority Queue is an extension of the queue with the
following properties.
• Every item has a priority associated with it.
• An element with high priority is dequeued before an element
with low priority.
• If two elements have the same priority, they are served
according to their order in the queue.
In the below priority queue, an element with a maximum ASCII value
will have the highest priority. The elements with higher priority are
served first.
How is Priority assigned to the elements in a Priority Queue?
In a priority queue, generally, the value of an element is considered for
assigning the priority.
For example, the element with the highest value is assigned the highest
priority and the element with the lowest value is assigned the lowest
priority. The reverse case can also be used i.e., the element with the
lowest value can be assigned the highest priority. Also, the priority can
be assigned according to our needs.
• Arrays
• Linked list
• Heap data structure
• Binary search tree
EXAMPLE: REF PRIORITY QUEUE PROGRAM(LAB EXERCISE)
DEQUE:
Deque is a type of queue in which insert and deletion can be performed
from either front or rear. It does not follow the FIFO rule. It is also
known as double-ended queue
Operations on Deque:
Deque consists of mainly the following operations:
• Insert Front
• Insert Rear
• Delete Front
• Delete Rear
Applications of Deque:
• It is used in job scheduling algorithms.
• It supports both stack and queue operations.
• The clockwise and anti-clockwise rotation operations in deque
are performed in O(1) time which is helpful in many problems.
Real-time Application of Deque:
• In a web browser’s history, recently visited URLs are added to
the front of the deque and the URL at the back of the deque is
removed after some specified number of operations of
insertions at the front.
• Storing a software application’s list of undo operations.
• In graph traversal algorithms such as breadth-first search
(BFS). BFS uses a deque to store nodes and performs
operations such as adding or removing nodes from both ends
of the deque.
• In task management systems to manage the order and priority
of incoming tasks. Tasks can be added to the front or back of
the deque depending on their priority or deadline.
• In queueing systems to manage the order of incoming
requests. Requests can be added to the front or back of the
deque depending on their priority or arrival time.
• In caching systems to cache frequently accessed data.
Deques can be used to store cached data and efficiently
support operations such as adding or removing data from both
ends of the deque.
Advantages of Deque:
• You are able to add and remove items from the both front and
back of the queue.
• Deques are faster in adding and removing the elements to the
end or beginning.
• The clockwise and anti-clockwise rotation operations are faster
in a deque.
• Dynamic Size: Deques can grow or shrink dynamically.
• Efficient Operations: Deques provide efficient O(1) time
complexity for inserting and removing elements from both
ends.
• Versatile: Deques can be used as stacks (LIFO) or queues
(FIFO), or as a combination of both.
• No Reallocation: Deques do not require reallocation of
memory when elements are inserted or removed.
• Thread Safe: Deques can be thread-safe if used with proper
synchronization.
• Cache-Friendly: Deques have a contiguous underlying
storage structure which makes them cache-friendly.
Disadvantages of Deque:
• Deque has no fixed limitations for the number of elements they
may contain. This interface supports capacity-restricted
deques as well as the deques with no fixed size limit.
• They are less memory efficient than a normal queue.
• Memory Overhead: Deques have higher memory overhead
compared to other data structures due to the extra pointers
used to maintain the double-ended structure.
• Synchronization: Deques can cause synchronization
issues if not used carefully in multi-threaded environments.
• Complex Implementation: Implementing a deque can be
complex and error-prone, especially if implementing it
manually.
• Not All Platforms: Deques may not be supported by all
platforms, and may need to be implemented manually.
• Not Suitable for Sorting: Deques are not designed for
sorting or searching, as these operations require linear time.
• Limited Functionality: Deques have limited functionality
compared to other data structures such as arrays, lists, or
trees.