Data Structures
Data Structures
UNIT-I
UNIT I
Introduction to Data Structure:
Arrays - Fundamentals, Representations, and Applications,
Sparse Matrices.
Stacks - Operations on stacks, Applications - Infix to postfix conversion,
evaluation of postfix expressions, Tower of Hanoi.
Queues - Operations and applications, Types - Circular Queue, Priority
Queue.
INTRODUCTION TO DATA STRUCTURES
Data Structure is a way of collecting and organizing data in such a
way that we can perform operations on these data in an effective way.
Ex:- Assume student’s name “Rohit" and age 20. Here “Rohit" is
of String data type and 20 is of integer data type.
We can organize this data as a record like Student record, which will
have both student's name and age in it. Now we can collect and store
student’s records in a file or database as a data structure.
Classifications of Data Structures
Data Structures are classified into two categories:
Representation of an array
We can represent an array in various ways in different programming languages.
Declaration of Array:-
1.data_type array_name[array_size];
Ex:-int marks[5]
Initialization of Array
The simplest way to initialize an array is by
using the index of each element. We can
initialize each element of the array by using the
index.
Consider the following example.
2.marks[0]=80;//initialization of array
2.marks[1]=60;
3.marks[2]=70;
4.marks[3]=85;
5.marks[4]=75;
Characteristics of Arrays in Data Structures
Fixed Size: Once an array is declared, its size cannot be changed.
Homogeneous Elements: All elements in an array must be of the same data
type, such as all integers, all floats, or all characters.
Indexed by Integers: Each element in an array is assigned a unique integer
called an index, which identifies its position within the array. Indexing usually
starts at 0.
Efficient Access: Because of the way arrays are stored in memory
(contiguously), accessing any element by its index is very efficient. This
direct access using the index is often referred to as "random access."
Advantages
1) Code Optimization: Less code to the access the data.
2) Ease of traversing: By using the for loop, we can retrieve the
elements of an array easily.
3) Ease of sorting: To sort the elements of the array, we need a few
lines of code only.
4) Random Access: We can access any element randomly using the
array.
Disadvantages
1) Fixed Size: Whatever size, we define at the time of declaration of
the array, we can't exceed the limit.
Applications of Array:
1.We can store a list of data elements belonging to the same data type.
2.Array acts as an auxiliary storage for other data structures.
3.The array also helps store data elements of a binary tree of the fixed
count.
4.Array also acts as a storage of matrices.
Types of Arrays
An array in C is a collection of elements of the same data type, stored in
contiguous memory locations. There are two types of arrays:
● One Dimensional Array
● Two Dimensional Array
For example, let's say you have an array of integers with 5 elements and the base address
of the array is 100. The size of each integer element is 4 bytes. To access the third
element a[2] of the array, you would use the following formula:
a[2] = 100 + 2 * 4 = 108
Address Calculation in Two Dimensional Array
To access an element in a 2D array, the computer needs to know its memory address. The
memory address of an element in a 2D array can be calculated using the following formula:
address = base_address + (row_index * num_columns + column_index) * size_of_element
Where:
● base_address: the memory address of the first element in the 2D array.
● row_index: the index of the row containing the element you want to access.
● column_index: the index of the column containing the element you want to access.
● num_columns: the number of columns in the 2D array.
● size_of_element: the size (in bytes) of each element in the 2D array.
For example, let's say you have a 2D array of integers with 3 rows and 4 columns, and the
base address of the array is 100. The size of each integer element is 4 bytes. To access the
element at row 1, column 0 which is a[1][0] you would use the following formula:
a[1][0] = 100 + (1 * 4 + 0) * 4 = 116
Basic operations
Traversal - This operation is used to print the elements of the array.
Insertion - It is used to add an element at a particular index.
Deletion - It is used to delete an element from a particular index.
Search - It is used to search an element using the given index or by the
value.
Update - It updates an element at a particular index.
Traversal Operation
Array traversal refers to the process of accessing each element of an array in a
sequential order.
Algorithm for Traversing an Array
Traversal (data,LB,UB)
Here data is array name and LB is Lower Bound (start) index of the first element of
an array. UB is Upper Bound (End) is the index of the last element
Step 1: Start
Step 2: [Initialize variable. ] Set i = LB
Step 3: Repeat steps 4 and 5 While i <= UB
Step 4: Apply process (Print ) to data[i].
Step 5: Increment i=i+1
Step 6: End of loop
Step 7: Stop
Insertion Operation
Insertion in an array refers to the process of adding a new element to a specific position
within the array
Step 1: Start
Step 2: [Initialize variable ] Set i = size - 1
Step 3: Repeat Step 4 and 5 While i >= pos-1
Step 4: [Move ith element forward. ] set arr[i+1] = arr[i]
Step 5: [Decrease counter. ] Set i = i - 1
Step 6: [End of step 3 loop. ]
Step 7: [Insert element. ] Set arr[pos-1] = item
Step 8: Stop
Deletion Operation
Deletion in an array means removing an element from an array
Algorithm to Delete an element from an Array:
Step 1: Start
Step 2: [Initialize variable] Set i = pos - 1
Step 3: Repeat Step 4 and 5 for i = pos - 1 to i < size
Step 4: [Move ith element left side ] set a[i] = a[i+1]
Step 5: [Incerement ] Set i = i + 1
Step 6: [End of step 03 loop. ]
Step 7: [Update Array Size] set size = size - 1
Step 8: Stop
SPARSE MATRICES
Sparse Matrix:-
A sparse matrix is a matrix that
contains a large number of zero
elements compared to non-zero
elements.
In such matrices, it is not efficient to
use traditional representations, which
store all elements, because a
significant amount of memory will
be wasted on storing zero elements.
Therefore, special techniques are
used to represent sparse matrices,
which can save a lot of memory.
Representation of Sparse Matirx
Sparse matrices can be represented using both arrays and linked lists.
#include <stdio.h>
int main(){
int sm[100][100], rows, cols, i, j, nonzero = 0;
printf("Enter no of rows & columns of the matrix: ");
scanf("%d %d", &rows, &cols);
printf("Enter the matrix elements:");
for (i = 0; i < rows; i++){
for (j = 0; j < cols; j++){
scanf("%d", &sm[i][j]);
if (sm[i][j] != 0){
nonzero++;
}}}
int fmatrix[3][nonzero];
int k=0;
for(int i=0; i<rows; i++) { OUTPUT:-
for(int j=0; j<cols; j++) { Enter no of rows & columns of the matrix:
if(sm[i][j]!=0) { 3
fmatrix[0][k] = i; 4
fmatrix[1][k] = j; Enter the matrix elements:
fmatrix[2][k] = sm[i][j]; 4
k++; 0
} } } 0
for(int i=0 ;i<rows; i++) { 3
for(int j=0; j<cols; j++) { 0
printf("%d ", fmatrix[i][j]); 2
} } } 0
0
6
1
0
0
001203104326
Linked List Representation of Sparse Matrix
Each node in the linked list contains the value of the non-zero element,
its column index, row index, and a pointer to the next node in the list.
1.Check if the stack is full (if the stack has a fixed size and is already at its
maximum capacity). If the stack is full, the push operation cannot be performed.
2.Increment the top pointer of the stack to move it to the next empty position (i.e.,
the position above the current top element).
3.Add the new element to the position pointed by the top pointer.
4.Update the size of the stack to reflect the addition of the new element.
Algorithm of PUSH Operation in Stack
PUSH(S,TOP,N,X)
Here S is Stack, TOP is Stack Pointer, N is the Maximum Size of the Stack,
X is new element to be inserted
Step 1: If TOP==N
Write "OVERFLOW"
Return
( End of IF Statement)
Step 2: TOP=TOP +1 (Increment the TOP)
Step 3: S[TOP] = X (Insert New Element)
Step 4 END
Program in C to perform PUSH Operation in Stack using Array.
#include <stdio.h>
#define MAX_SIZE 100
int stack[MAX_SIZE];
int top = -1;
void push(int);
int main()
{
push(10);
push(20);
push(30);
push(40);
push(50);
printf("Elements in the Stack\n");
for(int i=top; i>=0;i--)
{
printf("|%d|",stack[i]);
} OUTPUT:-
return 0; 10 pushed to stack
} 20 pushed to stack
void push(int element) 30 pushed to stack
{ 40 pushed to stack
if (top >= MAX_SIZE - 1) 50 pushed to stack
{ Elements in the Stack
printf("Stack Overflow"); |50||40||30||20||10|
}
else
{
top=top+1;
stack[top] = element;
printf("%d pushed to stack\n", element);
}
}
POP operation in a stack:
The POP operation in a stack is typically used in
conjunction with the "PUSH“ operation, which adds
an element to the top of the stack.
Together, these operations allow you to implement a
Last-In-First-Out (LIFO) data structure.
1.Check if the stack is empty. If the stack is
empty, return an error , as popping from an
empty stack is not allowed.
2.Otherwise, retrieve the topmost element from
the stack.
3.Decrement the stack pointer to point to the next
element in the stack.
4.Remove the topmost element from the stack.
5.Return the removed element if necessary.
Algorithm of POP Operation in Stack
POP(S,TOP,N,X)
Here S is Stack,
TOP is Stack Pointer,
N is the Maximum Size of the Stack,
X is element to be deleted
Step 1: If TOP==-1 (Stack Empty)
Write "Underflow"
Return
( End of IF Statement)
Step 2: X= S[TOP] (Delete Top Element)
Step 3: TOP=TOP - 1 (Decrement the Top)
Step 4 END
//Program in C to perform POP operation in Stack {
using Array printf("|%d|",stack[i]);
#include <stdio.h> }
#define MAX_SIZE 100 pop(50);
int stack[MAX_SIZE]; pop(40);
int top = -1; printf("Stack After Pop Operation\n");
void push(int); for(int i=top; i>=0;i--)
void pop(int); {
int main() printf("|%d|",stack[i]);
{ }
push(10); return 0;
push(20); }
push(30); void push(int element)
push(40); {
push(50); if (top >= MAX_SIZE - 1)
printf("Elements Available in the Stack\n"); {
for(int i=top; i>=0;i--) printf("Stack Overflow");
}
else
{
top=top+1; OUTPUT:-
stack[top] = element; 10 pushed to stack
printf("%d pushed to stack\n", element); 20 pushed to stack
}} 30 pushed to stack
void pop(int element) 40 pushed to stack
{ 50 pushed to stack
if (top == - 1) Elements Available in the Stack
{ |50||40||30||20||10|50 element
printf("Stack Underflow"); deleted from Stack
} 40 element deleted from Stack
else Stack After Pop Operation
{ |30||20||10|
element= stack[top];
top=top-1;
printf("%d element deleted from Stack\n",
element);
Applications of stacks :
Parenthesis Matching: In programming languages, parentheses are used to group
expressions and indicate the order of evaluation.
Parenthesis matching is a common problem where we need to check if a given
expression contains matching opening and closing parentheses. This can be
easily solved using a stack.
For Example X= a + (b*c), is a valid expression, it has same number of opening
brackets and closing brackets.
If the expression do not have same number of opening and closing brackets,
that expression will be invalid.
Compiler Design: Stacks are used in compiler design to check the validity of a
program's syntax. The stack is used to keep track of opening and closing
brackets, braces, and parentheses.
For example, if a program contains an opening brace {, it is pushed onto the
stack. When a closing brace } is encountered, the stack is popped to check if
the opening brace matches the closing brace.
Depth First Search: Stacks are used in graph algorithms such as Depth First Search
(DFS). The DFS algorithm visits all vertices in a graph by exploring as far as
possible along each branch before backtracking. The stack is used to keep track of
vertices that have been visited but not fully explored. Each time a vertex is visited, it
is pushed onto the stack. When all adjacent vertices have been visited, the vertex is
popped off the stack and the algorithm backtracks.
•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
1) Arithmetic expressions
Infix Notation:-
The expression which is in the normal format i,e the operator lies in between the operand
Ex: a+b,a*b
Syntax:<Operand><Operator><Operand>
Step 1: IF FRONT = -1
Write " UNDERFLOW "
Goto Step 4
[END of IF]
Step 2: SET VAL = QUEUE[FRONT]
Step 3: IF FRONT = REAR
SET FRONT = REAR = -1
ELSE
IF FRONT = MAX -1
SET FRONT = 0
ELSE
SET FRONT = FRONT + 1
[END of IF]
[END OF IF]
Implementation of circular queue using Array
https://onlinegdb.com/_jIUnzofuH
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. Insertion in priority queue takes place based on the arrival, while deletion in
the priority queue occurs based on the priority. Priority queue is mainly used to implement
the CPU scheduling algorithms.
Insertion in priority queue takes place based on the arrival, while deletion in the priority
queue occurs based on the priority. Priority queue is mainly used to implement the CPU
scheduling algorithms.
There are two types of priority queues
•Ascending priority queue - In ascending priority queue, elements can be inserted in
arbitrary order, but only smallest can be deleted first. Suppose an array with elements 7, 5,
and 3 in the same order, so, insertion can be done with the same sequence, but the order of
deleting the elements is 3, 5, 7.
•Descending priority queue - In descending priority queue, elements can be inserted in
arbitrary order, but only the largest element can be deleted first. Suppose an array with
elements 7, 3, and 5 in the same order, so, insertion can be done with the same sequence,
but the order of deleting the elements is 7, 5, 3.
UNIT-II
UNIT II
Linked Lists: Singly/Linear Linked Lists,
Operations - Insertion and deletion from a list, Linked List
Implementation of Stacks and Queues,
Doubly and Circular Linked Lists, Applications.
Linked Lists:
Singly/Linear Linked
Lists
Linked List:-
The linked list is a linear data structure that contains a sequence of elements such that each
element links to its next element in the sequence. Each element in a linked list is called
"Node".
}
printf("Item pushed"); } }
Deleting a node from the stack (POP void pop()
operation) {
Deleting a node from the top of stack is int item;
referred to as pop operation. Deleting a node struct node *ptr;
from the linked list implementation of stack is if (head == NULL)
different from that in the array {
implementation. printf("Underflow");
Check for the underflow condition: The }
underflow condition occurs when we try to else
pop from an already empty stack. The stack {
will be empty if the head pointer of the list item = head->val;
points to null. ptr = head;
Adjust the head pointer accordingly: In head = head->next;
stack, the elements are popped only from one free(ptr);
end, therefore, the value stored in the head printf("Item popped");
pointer must be deleted and the node must be
freed. The next node of the head node now }
becomes the head node. }
Display the nodes (Traversing)
Displaying all the nodes of a stack needs void display()
traversing all the nodes of the linked list {
organized in the form of stack. int i;
Copy the head pointer into a temporary struct node *ptr;
pointer. ptr=head;
Move the temporary pointer through all if(ptr == NULL)
the nodes of the list and print the value {
field attached to every node. printf("Stack is empty\n");
}
else
{
printf("Printing Stack elements \n");
while(ptr!=NULL)
{
printf("%d\n",ptr->val);
ptr = ptr->next;
} } }
Double Linked List:-
Double linked list is a sequence of elements in which every element has links to its previous
element and next element in the sequence.
In a double linked list, every node has a link to its previous node and next node. So, we can
traverse forward by using the next field and can traverse backward by using the previous field.
Every node in a double linked list contains three fields
Here, 'link1' field is used to store the address of the previous node in the sequence, 'link2' field
is used to store the address of the next node in the sequence and 'data' field is used to store the
actual value of that node.
Operations on Double Linked List
In a double linked list, we perform the following operations...
1.Insertion
2.Deletion
3.Display
Insertion
4.Inserting At Beginning of the list
5.Inserting At End of the list
6.Inserting At Specific location in the list
Inserting At Beginning of the list
•Step 1 - Create a newNode with given value and newNode → previous as NULL.
•Step 2 - Check whether list is Empty (head == NULL)
•Step 3 - If it is Empty then, assign NULL to newNode → next and newNode to head.
•Step 4 - If it is not Empty then, assign head to newNode → next and newNode to head.
Root:- In a tree data structure, the first node is called as Root Node. Every tree
must have a root node. We can say that the root node is the origin of the tree data
structure. In any tree, there must be only one root node. We never have multiple
root nodes in a tree.
Edge:- In a tree data structure, the connecting link between any two
nodes is called as EDGE. In a tree with 'N' number of nodes there will be
a maximum of 'N-1' number of edges.
Parent
In a tree data structure, the node which is a predecessor of any node is called
as PARENT NODE. In simple words, the node which has a branch from it to
any other node is called a parent node. Parent node can also be defined as "The
node which has child / children".
Child
In a tree data structure, the node which is descendant of any node is called
as CHILD Node. In simple words, the node which has a link from its parent
node is called as child node. In a tree, any parent node can have any number of
child nodes. In a tree, all the nodes except root are child nodes.
Siblings:-In a tree data structure, nodes which belong to same Parent are called
as SIBLINGS NODES.
Leaf:- In a tree data structure, the node which does not have a child is
called as LEAF Node. In simple words, a leaf is a node with no child.
In a tree data structure, the leaf nodes are also called as External Nodes.
External node is also a node with no child. In a tree, leaf node is also
called as 'Terminal' node.
Internal Nodes:- In a tree data structure, the node which has atleast one child is
called as INTERNAL Node. In simple words, an internal node is a node with
atleast one child.
In a tree data structure, nodes other than leaf nodes are called as Internal
Nodes. The root node is also said to be Internal Node if the tree has more than
one node. Internal nodes are also called as 'Non-Terminal' nodes.
Degree:- In a tree data structure, the total number of children of a node is
called as DEGREE of that Node. In simple words, the Degree of a node is
total number of children it has. The highest degree of a node among all the
nodes in a tree is called as 'Degree of Tree'
Level:- In a tree data structure, the root node is said to be at Level 0 and the
children of root node are at Level 1 and the children of the nodes which are at
Level 1 will be at Level 2 and so on... In simple words, in a tree each step from
top to bottom is called as a Level and the Level count starts with '0' and
incremented by one at each level (Step).
Height:- In a tree data structure, the total number of edges from leaf node to
a particular node in the longest path is called as HEIGHT of that Node. In a
tree, height of the root node is said to be height of the tree. In a tree, height
of all leaf nodes is '0'.
Depth:- In a tree data structure, the total number of egdes from root node to a
particular node is called as DEPTH of that Node. In a tree, the total number of
edges from root node to a leaf node in the longest path is said to be Depth of the
tree. In simple words, the highest depth of any leaf node in a tree is said to be
depth of that tree. In a tree, depth of the root node is '0'.
Path:- In a tree data structure, the sequence of Nodes and Edges from one
node to another node is called as PATH between that two Nodes. Length
of a Path is total number of nodes in that path.
In below example the path A - B - E - J has length 4.
Sub Tree:- In a tree data structure, each child from a node forms a subtree
recursively. Every child node will form a subtree on its parent node.
Tree Representation
A tree data structure can be represented in two methods.
List Representation
Left Child - Right Sibling Representation
List Representation
In this representation, we use two types of nodes one for representing the
node with data called 'data node' and another for representing only references
called 'reference node’.
We start with a 'data node' from the root node in the tree. Then it is linked to
an internal node through a 'reference node' which is further linked to any
other node directly. This process repeats for all the nodes in the tree.
Left Child - Right Sibling Representation
In this representation, we use a list with one type of node which consists of
three fields namely Data field, Left child reference field and Right sibling
reference field.
Data field stores the actual value of a node, left reference field stores the
address of the left child and right reference field stores the address of the
right sibling node.
In this representation, every node's data field stores the actual value of that
node.
If that node has left a child, then left reference field stores the address of
that left child node otherwise stores NULL.
If that node has the right sibling, then right reference field stores the address
of right sibling node otherwise stores NULL.
Applications of trees:-
•Storing naturally hierarchical data: Trees are used to store the data in the hierarchical
structure.
•Organize data: It is used to organize data for efficient insertion, deletion and searching.
•Trie: It is a special kind of tree that is used to store the dictionary. It is a fast and efficient
way for dynamic spell checking.
•Heap: It is also a tree data structure implemented using arrays. It is used to implement
priority queues.
•B-Tree and B+Tree: B-Tree and B+Tree are the tree data structures used to implement
indexing in databases.
•Routing table: The tree data structure is also used to store the data in routing tables in the
routers.
•Parse Trees: The tree data structure useful in creating parse tree for evaluating arithmetic
expressions.
TREE TRAVERSALS
Tree traversals:-
The term 'tree traversal' means traversing or visiting each node of a tree. There is
a single way to traverse the linear data structure such as linked list, queue, and
stack. Whereas, there are multiple ways to traverse a tree that are listed as follows
-
•Preorder traversal
•Inorder traversal
•Postorder traversal
Algorithm for preorder traversal
Preorder traversal 1.Until all nodes of the tree are not visited
This technique follows the 'root left right' policy.
2.Step 1 - Visit the root node
It means that, first root node is visited after that the
3.Step2 - Traverse the left subtree recursively.
left subtree is traversed recursively, and finally,
4.Step 3 - Traverse the right subtree recursively
right subtree is recursively traversed.
As the root node is traversed before (or pre) the
left and right subtree, it is called preorder traversal.
So, in a preorder traversal, each node is visited
before both of its subtrees.
It is also known as a
left-skewed tree as all
the nodes have a left
child only.
Balanced Binary Tree
The balanced binary tree is a tree in which both the left and right trees differ by atmost 1.
Binary Tree Representations
A binary tree data structure is represented using
two methods.
1. Array Representation
2. Linked List Representation
Array Representation of Binary Tree
In array representation of a binary tree, we use one-dimensional array (1-D Array) to
represent a binary tree.
To represent a binary tree of depth 'n' using array representation, we need one
dimensional array with a maximum size of 2n + 1.
Linked List Representation of Binary
Tree
We use a double linked list to represent a
binary tree. In a double linked list, every
node consists of three fields. First field
for storing left child address, second for
storing actual data and third for storing
right child address.
Binary Tree Operations
Binary trees support several fundamental
operations, including insertion, deletion, After inserting a node 6,
searching, and traversals
1. Insertion
Insertion involves adding a new node to the
binary tree. In a binary tree, a new node is usually
inserted at the first available position in level
order to maintain the completeness of the tree.
Deletion
Deletion involves removing a node from the binary tree. In a binary tree, the
node to be deleted is replaced by the deepest and rightmost node to maintain the
tree's structure.
Search
Searching involves finding a node with a given value in the binary tree. The search
operation can be implemented using any traversal method (in-order, pre-order, post-
order, or level-order).
1
2
3
Algorithm to search an element in Binary search tree
Search (root, item)
Step 1 - if (item = root → data) or (root = NULL)
return root
else if (item < root → data)
return Search(root → left, item)
else
return Search(root → right, item)
END if
Step 2 - END
Deletion in Binary Search tree
•The node to be deleted is the leaf node, or,
•The node to be deleted has only one child, and,
•The node to be deleted has two children
Step 2: The next element is 33. As we know that insertion in the binary tree always
starts from the left side so 44 will be added at the left of 33
Step 3: The next element is 77 and it will be added to the right of the 44
As we can observe in the above tree that it does not satisfy the max heap property, i.e.,
parent node 44 is less than the child 77. So, we will swap these two values
Step 4: The next element is 11. The node 11 is added to the left of 33
Step 5: The next element is 55. To make it a complete binary tree, we will add the
node 55 to the right of 33
As we can observe in the above figure that it does not satisfy the property of the max
heap because 33<55, so we will swap these two values
Step 6: The next element is 88. The left subtree is completed so we will add 88 to the left
of 44
As we can observe in the above figure that it does not satisfy the property of the max
heap because 44<88, so we will swap these two values
Step 7: As we can observe in the above figure that 88 >77,so swap these values
Step 8:- The next element is 66. To make a complete binary tree, we will add the 66
element to the right side of 77
B TREE
B-Tree(Height balanced M way search Tree)