DATA STRUCTURES AND ALGORITHMS Unit II 2024 REGULATION
DATA STRUCTURES AND ALGORITHMS Unit II 2024 REGULATION
A Stack is a linear data structure where insertion and deletion of items takes
place at one end called top of the stack. A Stack is defined as a data structure
which operates on a last-in first-out basis.
So it is also is referred as Last-inFirst-out( LIFO). Stack uses a single index
or pointer to keep track of the information in the stack.
A stack pointer keeps track of the current position on the stack. When an
element is placed on the stack, it is said to be pushed on the stack.
When an object is removed from the stack, it is said to be popped off the
stack. Two additional terms almost always used with stacks are overflow,
which occurs when we try to push more information on a stack that it can
hold, and underflow, which occurs when we try to pop an item off a stack
which is empty.
void stack::push()
else { }
top++;
cin>>data;
stk[top]=data;
cout<<"Pushed Sucesfully....\n"
To remove an item, first extract the data from top position in the stack and then
decrement the stack pointer, top.
template<class T>
void stack::pop()
if(top= =-1)
cout<<"Stack is Underflow";
else { }
data=stk[top];
top--;
PUSH operation
POP operation
o Before deleting the element from the stack, we check whether the stack is
empty.
o If we try to delete the element from the empty stack, then
the underflow condition occurs.
o If the stack is not empty, we first access the element which is pointed by
the top
o Once the pop operation is performed, the top is decremented by 1,
i.e., top=top-1.
Applications of Stack
int main()
{
cout<<"Hello"; }
cout<<"javaTpoi}
o String reversal: Stack is also used for reversing a string. For example, we want
to reverse a "javaTpoint" string, so we can achieve this with the help of a stack
First, we push all the characters of the string in a stack until we reach the null
character.
o After pushing all the characters, we start taking out the character one by one
until we reach the bottom of the stack.
o UNDO/REDO: It can also be used for performing UNDO/REDO operations.
For example, we have an editor in which we write 'a', then 'b', and then 'c';
therefore, the text written in an editor is abc. So, there are three states, a, ab, and
abc, which are stored in a stack.
o There would be two stacks in which one stack shows UNDO state, and the
other.
o Recursion: The recursion means that the function is calling itself again. To
maintain the previous states, the compiler creates a system stack in which all
the previous records of the function are maintained.
o DFS(Depth First Search): This search is implemented on a Graph, and Graph
uses the stack data structure.
o Backtracking: Suppose we have to create a path to solve a maze problem. If
we are moving in a particular path, and we realize that we come on the wrong
way. In order to come at the beginning of the path to create a new path, we have
to use the stack data structure.
o Expression conversion: Stack can also be used for expression conversion. This
is one of the most important applications of stack. The list of the expression
conversion is given below:
Infix to prefix
Infix to postfix
Prefix to infix
Prefix to postfix
Postfix to infix
Memory management:
Infix Notation
We write expression in infix notation, e.g. a - b + c, where operators are used in-
between operands. It is easy for us humans to read, write, and speak in infix
notation but the same does not go well with computing devices.
Prefix Notation
Postfix Notation
This notation style is known as Reversed Polish Notation. In this notation style,
the operator is postfixed to the operands i.e., the operator is written after the
operands. For example, ab+. This is equivalent to its infix notation a + b.
2 (a + b) ∗ c ∗+abc ab+c∗
3 a ∗ (b + c) ∗a+bc abc+∗
5 (a + b) ∗ (c + d) ∗+ab+cd ab+cd+∗
Precedence
When an operand is in between two different operators, which operator will take
the operand first, is decided by the precedence of an operator over others. For
example
Associativity
Associativity describes the rule where operators with the same precedence appear
in an expression. For example, in expression a + b − c, both + and − have the same
precedence, then which part of the expression will be evaluated first, is determined
by associativity of those operators. Here, both + and − are left associative, so the
expression will be evaluated as (a + b) − c.
Infix expression:
The expression of the form “a operator b” (a + b) i.e.,
when an operator is in-between every pair of operands.
Postfix expression: The expression of the form “a b operator” (ab+) i.e., When
every pair of operands is followed by an operator.
Examples:
Input: A + B * C + D
Output: ABC*+D+
Input: ((A + B) – C * (D / E)) + F
Output: AB+CDE/*-F+
Postfix expression: 2 3 4 * +
34*+ 2 Push 3
4*+ 32 Push 4
QUEUE ADT
A queue is an ordered collection of data such that the data is inserted at one end
and deleted from another end. The key difference when compared stacks is that in
a queue the information stored is processed first-in first-out or FIFO. In other
words the information receive from a queue comes in the same order that it was
placed on the queue.
Representing a Queue:
One of the most common way to implement a queue is using array. An easy way to
do so is to define an array Queue, and two additional variables front and rear.
The rules for manipulating these variables are simple:
Each time information is added to the queue, increment rear.
Each time information is taken from the queue, increment front.
Whenever front >rear or front=rear=-1 the queue is empty.
Array implementation of a Queue do have drawbacks. The maximum queue size
has to be set at compile time, rather than at run time. Space can be wasted, if we do
not use the full capacity of the array.
Operations on Queue:
A queue have two basic operations:
a)adding new item to the queue
b) removing items fromqueue.
The operation of adding new item on the queue occurs only at one end of the
queue called the rear or back. The operation of removing items of the queue occurs
at the other end called the front.
For insertion and deletion of an element from a queue, the array elements begin at
0 and the maximum elements of the array is maxSize.
The variable front will hold the index of the item that is considered the front of the
queue, while the rear variable will hold the index of the last item in the queue.
Assume that initially the front and rear variables are initialized to -1. Like stacks,
underflow and overflow conditions are to be checked before operations in a queue.
Queue empty or underflow condition is
if((front>rear)
front= =-1) cout
Queue Full or overflow condition is
if((rear==max) cout
Types of Queue
What is a Queue
Queue is the data structure that is similar to the queue in the real world. A queue is
a data structure in which whatever comes first will go out first, and it follows the
FIFO (First-In-First-Out) policy.
Queue can also be defined as the list or collection in which the insertion is done
from one end known as the rear end or the tail of the queue, whereas the deletion
is done from another end known as the front end or the head of the queue.
Linear Queue, an insertion takes place from one end while the deletion occurs from
another end.
The end at which the insertion takes place is known as the rear end, and the end at
which the deletion takes place is known as front end. It strictly follows the FIFO
rule.
Linear Queue, an insertion takes place from one end while the deletion occurs
from another end. The end at which the insertion takes place is known as the rear
end, and the end at which the deletion takes place is known as front end. It strictly
follows the FIFO rule.
Circular Queue
Circular Queue, all the nodes are represented as circular. It is similar to the linear
Queue except that the last element of the queue is connected to the first element. It
is also known as Ring Buffer, as all the ends are connected to another end.
Priority Queue
It is a special type of queue in which the elements are arranged based on the
priority. It is a special type of queue data structure in which every element has a
priority associated with it. Suppose some elements occur with the same priority,
they will be arranged according to the FIFO principle.
Deque (or, Double Ended Queue)
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 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.
Two Types:
Queues are most commonly observed in customer service systems like banking,
airports, and customer helplines. Customers are served in the order they arrive,
ensuring fairness. This is a straightforward implementation of a simple queue.
2. Print Spooling
When multiple print jobs are submitted to a printer, they are stored in a queue until
processed one by one. The print spooler is an example of a queue application in
real life.
In traffic control and toll booths, vehicles often form a queue as they wait for their
turn. This is an example of queue real-time applications where vehicles are
processed in the order they arrive.
In operating systems, CPU scheduling and task scheduling are based on queues,
where processes are executed in the order they are ready to run. Round-robin
scheduling in operating systems is often implemented using a circular queue.
In networking, data packets arriving at a router are stored in a queue before being
transmitted to the destination. This helps in managing traffic flow and prevents
packet loss. Network traffic management heavily relies on queues.
In simulation systems, queues are used to model and simulate real-world systems
such as manufacturing processes, where resources are allocated based on queue
management. For instance, banking systems simulate customer wait times, while
call centers use queues to manage incoming calls.
3. Memory Management
4. Event-driven Programming
A linked list is a type of linear data structure that occurs when the data elements do
not reside in consecutive memory regions. A linked list's components are
connected using pointers (entities that lead to the next member).
A linked list comprises of nodes, each of which has an information field and a
reference (link) to the subsequent node in that list.
Following are the various operations to perform the required action on a linked list:
Traversal - To access each element of the linked list.
Insertion
It’s more than a one-step activity. First, we create a node with the same structure
and specify the location where we’ll insert it.
Once, it’s located, we’ll change the reference link of the previous node to the node
that is next to our target node.
You can search an element on a linked list using a loop using the following steps.
We are finding item on a linked list.
Make head as the current node.
Run a loop until the current node is NULL because the last element points
to NULL.
In each iteration, check if the key of the node is equal to item. If it the key matches
the item, return true otherwise return false.
Example
bool searchNode(struct Node** head_ref, int key) {
struct Node* current = *head_ref;
We will use a simple sorting algorithm, Bubble Sort, to sort the elements of a
linked list in ascending order below.
1. Make the head as the current node and create another node index for later use.
2. If head is null, return.
3. Else, run a loop till the last node (i.e. NULL).
4. In each iteration, follow the following step 5-6.
Displaying the contents of a linked list is very simple. We keep moving the temp
node to the next one and display its contents.
When temp is NULL, we know that we have reached the end of the linked list so
we get out of the while loop.
Example program:
while(temp != NULL) {
printf("%d --->",temp->data);
temp = temp->next; }
Singly linked lists contain two "buckets" in one node; one bucket holds the data
and the other bucket holds the address of the next node of the list. Traversals can
be done in one direction only as there is only a single link between two nodes of
the same list.
Doubly Linked Lists contain three "buckets" in one node; one bucket holds the
data and the other buckets hold the addresses of the previous and next nodes in the
list. The list is traversed twice as the nodes in the list are connected to each other
from both sides.
Circular linked lists can exist in both singly linked list and doubly linked list.
Since the last node and the first node of the circular linked list are connected, the
traversal in this linked list will go on forever until it is broken.
Insertion
This operation is beneficial for adding a new element to the linked list, which can
be done at any position in the list, including the tail or the head.
Deletion
This operation is beneficial for removing an element from a linked list data
structure. This can also be done at any position on the list.
Display
With this operation, one can visit each element in the linked list in a specific order
from head to tail.
Search
This operation allows one to search for a particular element in the linked list data
structure. This can be done by crossing the list and comparing every element to the
target.
Look here to know more about the Real-time application of data structures.
Along with the advantages, some disadvantages linked list data structure offers:
Sequential access: Linked lists have poor cache locality and significant
memory overhead.
Absence of random access: As linked lists cannot use random access,
accessing entries directly from an index is impossible.
Complexity: The implementation and upkeep of linked lists can be more
difficult than those of arrays.