ACSD11
ACSD11
Page | 1
DATA STRUCTURES LABORATORY COURSE CONTENT
S No. Topic Name Page No.
1. Getting Started Exercises 5
a. Sum of last digits of two given numbers
b. Is N an exact multiple of M?
c. Combine Strings
d. Even or Odd
e. Second last digit of a given number
f. Alternate String Combiner
g. Padovan Sequence
h. Leaders in an array
i. Find the Value of a Number Raised to its Reverse
j. Mean of Array using Recursion
2. Searching 12
a. Linear / Sequential Search
b. Binary Search
c. Uniform Binary Search
d. Interpolation Search
e. Fibonacci Search
3. Sorting 17
a. Bubble Sorting
b. Selection Sort
c. Insertion Sort
4. Divide and Conquer 21
a. Quick Sort
b. Merge Sort
c. Heap Sort
d. Radix Sort
e. Shell Sort
5. Stack 28
a. Implementation of Stack
b. Balanced Parenthesis Checking
c. Evaluation of Postfix Expression
d. Infix to Postfix Expression Conversion
e. Reverse a Stack
6. Queue 33
a. Linear Queue
b. Stack using Queues
c. Queue using Stacks
d. Circular Queue
e. Deque (Doubly Ended Queue)
7. Linked List 39
a. Singly Linked List
b. Linked List Cycle
c. Remove Linked List Elements
Page | 2
d. Reverse Linked List
e. Palindrome Linked List
f. Middle of the Linked List
g. Convert Binary Number in a Linked List to Integer
8. Circular Single Linked List and Doubly Linked List 46
a. Circular Linked List
b. Doubly Linked List
c. Sorted Merge of Two Sorted Doubly Circular Linked Lists
d. Delete all occurrences of a given key in a Doubly Linked List
e. Delete a Doubly Linked List Node at a Given Position
9. Trees 53
a. Tree Creation and Basic Tree Terminologies
b. Binary Tree Traversal Techniques
c. Insertion in a Binary Tree in Level Order
d. Finding the Maximum Height or Depth of a Binary Tree
e. Deletion in a Binary Tree
10. Binary Search Tree (BST) 60
a. Searching in Binary Search Tree
b. Find the node with Minimum Value in a BST
c. Check if a Binary Tree is BST or not
d. Second Largest Element in BST
e. Insertion in Binary Search Tree (BST)
11. AVL Tree 68
a. Insertion in an AVL Tree
b. Deletion in an AVL Tree
c. Count Greater Nodes in AVL Tree
d. Minimum Number of Nodes in an AVL Tree with given Heigh t
12. Graph Traversal 73
a. Breadth First Search
b. Depth First Search
c. Best First Search (Informed Search)
d. Breadth First Traversal of a Graph
e. Depth First Search (DFS) for Disconnected Graph
13. Minimum Spanning Tree (MST) 80
a. Kruskal’s Algorithm
b. Prim’s Algorithm
c. Total Number of Spanning Trees in a Graph
d. Minimum Product Spanning Tree
14. Final Notes 90
Page | 3
IV. COURSE CONTENT:
Note: Students are encouraged to bring their own laptops for laboratory
practice sessions.
import java.util.Scanner;
class AddLastDigitsFunction
{
int addLastDigits(int n1, int n2)
{
# Write code here
}
Page | 4
}
Page | 5
# Write code here
}
Page | 6
1.5 Second last digit of a given number
Write a function that returns the second last digit of the given number. Second last digit is being referred
to the digit in the tens place in the given number.
Example: if the given number is 197, the second last digit is 9.
Note 1: The second last digit should be returned as a positive number. i.e. if the given number is -197, the
second last digit is 9.
Note 2: If the given number is a single digit number, then the second last digit does not exist. In such cases,
the function should return -1. i.e. if the given number is 5, the second last digit should be returned as -1.
Input: 197
Output: 9
Input: 5
Output: -1
Input: -197
Output: 9
Page | 7
# write code here
}
}
import java.util.ArrayList;
import java.util.List;
Page | 8
public class ArrayLeaders
{
public static List<Integer> findArrayLeaders(int[] arr)
{
# write code here
}
public static void main(String[] args)
{
# write code here
}
}
Input: N = 57, R = 75
Output: 262042770
Explanation: 5775 modulo 109+7 gives us the result as 262042770
public class NumberPower
{
public static long powerOfReverse(int N, int R)
{
# write code here
}
public static void main(String[] args)
{
# write code here
}
}
Page | 9
public static double findArrayMean(int[] arr)
{
# write code here
}
public static void main(String[] args)
{
# write code here
}
}
Try:
1. Kth Smallest Element: Given an array arr[] and an integer k where k is smaller than the size of the array,
the task is to find the kth smallest element in the given array. It is given that all array elements are distinct.
Note: l and r denotes the starting and ending index of the array.
Input: n = 6, arr[] = {7, 10, 4, 3, 20, 15}, k = 3, l = 0, r = 5
Output: 7
Explanation: 3rd smallest element in the given array is 7.
Input: n = 5, arr[] = {7, 10, 4, 20, 15}, k = 4, l=0 r=4
Output: 15
Page | 10
2. Searching
2.1 Linear / Sequential Search
Linear search is defined as the searching algorithm where the list or data set is traversed from one end to
find the desired value. Given an array arr[] of n elements, write a recursive function to search a given element
x in arr[].
Input: arr[] = {10, 20, 80, 30, 60, 50, 110, 100, 130, 170}
x = 110;
Output: 6
Element x is present at index 6
Input: arr[] = {10, 20, 80, 30, 60, 50, 110, 100, 130, 170}
x = 175;
Output: -1
Element x is not present in arr[].
Page | 11
Binary Search is defined as a searching algorithm used in a sorted array by repeatedly dividing the search
interval in half. The idea of binary search is to use the information that the array is sorted and reduce the
time complexity to O(log N).
Input: arr = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
Output: target = 23
Element 23 is present at index 5
Page | 12
public static void main(String[] args)
{
# write code here
}
}
The algorithm is very similar to Binary Search algorithm, the only difference is a lookup table is created for
an array and the lookup table is used to modify the index of the pointer in the array which makes the search
faster. Instead of maintaining lower and upper bound the algorithm maintains an index and the index is
modified using the lookup table.
Interpolation search can take longer to implement than binary search, as it requires the use of additional
calculations to estimate the position of the target element.
Page | 13
Input: arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Output: target = 5
Page | 14
iv. Else x is greater than the element, move the three Fibonacci variables one Fibonacci down.
Reset offset to index. Together these indicate the elimination of approximately front one-third
of the remaining array.
3. Since there might be a single element remaining for comparison, check if fibMm1 is 1. If Yes, compare
x with that remaining element. If match, return index.
Page | 15
3. Sorting
3.1 Bubble Sort
Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements if
they are in the wrong order. This algorithm is not suitable for large data sets as its average and worst-case
time complexity is quite high.
Second Pass:
Third Pass:
import java.util.Scanner;
class BubbleSortExample
{
public static void main(String[] args)
Page | 16
{
# write code here
}
}
Second Pass: For the second position, where 25 is present, again traverse the rest of the array in a sequential
manner. After traversing, we found that 12 is the second lowest value in the array and it should appear at
the second place in the array, thus swap these values.
Third Pass: Now, for third place, where 25 is present again traverse the rest of the array and find the third
least value present in the array. While traversing, 22 came out to be the third least value and it should
appear at the third place in the array, thus swap 22 with element present at third position.
Page | 17
Fourth Pass: Similarly, for fourth position traverse the rest of the array and find the fourth least element in
the array. As 25 is the 4th lowest value hence, it will place at the fourth position.
Fifth Pass: At last the largest value present in the array automatically get placed at the last position in the
array. The resulted array is the sorted array.
import java.util.Scanner;
class SelectionSortExample
{
public static void main(String[] args)
{
# write code here
}
Page | 18
Input: arr = [4, 3, 2, 10, 12, 1, 5, 6]
Output: arr = [1, 2, 3, 4, 5, 6, 10, 12]
import java.util.Scanner;
class InsertionSortExample
{
public static void main(String[] args)
{
# write code here
}
Page | 19
4. Divide and Conquer
4.1 Quick Sort
QuickSort is a sorting algorithm based on the Divide and Conquer algorithm that picks an element as a
pivot and partitions the given array around the picked pivot by placing the pivot in its correct position in
the sorted array. The key process in quickSort is a partition(). The target of partitions is to place the pivot
(any element can be chosen to be a pivot) at its correct position in the sorted array and put all smaller
elements to the left of the pivot, and all greater elements to the right of the pivot. Partition is done
recursively on each side of the pivot after the pivot is placed in its correct position and this finally sorts the
array.
Page | 20
i = (start - 1) // Index of smaller element and indicates the
// right position of pivot found so far
for (j = start; j <= end- 1; j++)
{
// If current element is smaller than the pivot
if (arr[j] < pivot)
{
i++; // increment index of smaller element
swap arr[i] and arr[j]
}
}
swap arr[i + 1] and arr[end])
return (i + 1)
}
import java.util.Scanner;
class QuickSortExample
{
public static void main(String[] args)
{
# write code here
}
Page | 21
Input: arr = [12, 11, 13, 5, 6, 7]
Output: arr = [5, 6, 7, 11, 12, 13]
import java.util.Scanner;
class MergeSortExample
{
public static void main(String[] args)
{
# write code here
}
public static void merge(int[] arr, int low, int mid, int high)
{
# write code here
}
}
Page | 22
• Swap the root element of the heap (which is the largest element) with the last element of the
heap.
• Remove the last element of the heap (which is now in the correct position).
• Heapify the remaining elements of the heap.
• The sorted array is obtained by reversing the order of the elements in the input array.
import java.util.Scanner;
class HeapSortExample
{
public static void main(String[] args)
{
# write code here
}
To perform radix sort on the array [170, 45, 75, 90, 802, 24, 2, 66], we follow these steps:
Page | 23
Step 1: Find the largest element in the array, which is 802. It has three digits, so we will iterate three times,
once for each significant place.
Step 2: Sort the elements based on the unit place digits (X=0). We use a stable sorting technique, such as
counting sort, to sort the digits at each significant place.
Page | 24
Step 5: The array is now sorted in ascending order.
The final sorted array using radix sort is [2, 24, 45, 66, 75, 90, 170, 802]
import java.util.Arrays;
class RadixSortExample
{
public static void main(String[] args)
{
# write code here
}
Page | 25
Shell Sort Procedure:
1. Initialize the value of gap size h
2. Divide the list into smaller sub-part. Each must have equal intervals to h
3. Sort these sub-lists using insertion sort
4. Repeat this step 1 until the list is sorted.
5. Print a sorted list.
Procedure Shell_Sort(Array, N)
While Gap < Length(Array) /3 :
Gap = ( Interval * 3 ) + 1
End While Loop
While Gap > 0 :
For (Outer = Gap; Outer < Length(Array); Outer++):
Insertion_Value = Array[Outer]
Inner = Outer;
While Inner > Gap-1 And Array[Inner – Gap] >= Insertion_Value:
Array[Inner] = Array[Inner – Gap]
Inner = Inner – Gap
End While Loop
Array[Inner] = Insertion_Value
End For Loop
Gap = (Gap -1) /3;
End While Loop
End Shell_Sort
import java.util.Scanner;
class ShellSortExample
{
public static void main(String[] args)
{
# write code here
}
Page | 26
5. Stack
5.1 Implementation of Stack
A stack is a linear data structure that stores items in a Last-In/First-Out (LIFO) or First-In/Last-Out (FILO)
manner. In stack, a new element is added at one end and an element is removed from that end only. The
insert and delete operations are often called push and pop.
class Stack
{
private int maxSize;
private int top;
private int[] stackArray;
Page | 27
public boolean isFull()
{
# write code here
}
}
class StackExample
{
public static void main(String[] args)
{
Stack stack = new Stack(5);
stack.push(10);
stack.push(20);
stack.push(30);
stack.pop();
stack.peek();
stack.push(40);
stack.push(50);
stack.push(60);
}
}
import java.util.Stack;
class BalancedParenthesisChecker
{
public static boolean isBalanced(String expression)
{
# write code here
}
Page | 28
5.3 Evaluation of Postfix Expression
Given a postfix expression, the task is to evaluate the postfix expression. Postfix expression: The expression
of the form “a b operator” (ab+) i.e., when a pair of operands is followed by an operator.
Input: str = “2 3 1 * + 9 -“
Output: -4
Explanation: If the expression is converted into an infix expression, it will be 2 + (3 * 1) – 9 = 5 – 9 = -4.
Input: str = “100 200 + 2 / 5 * 7 +”
Output: 757
Procedure for evaluation postfix expression using stack:
• Create a stack to store operands (or values).
• Scan the given expression from left to right and do the following for every scanned element.
o If the element is a number, push it into the stack.
o If the element is an operator, pop operands for the operator from the stack. Evaluate the
operator and push the result back to the stack.
• When the expression is ended, the number in the stack is the final answer.
import java.util.Stack;
class PostfixEvaluator
{
public static int evaluatePostfix(String expression)
{
# write code here
}
Page | 29
• If the precedence and associativity of the scanned operator are greater than the precedence and
associativity of the operator in the stack [or the stack is empty or the stack contains a ‘(‘ ], then
push it in the stack. [‘^‘ operator is right associative and other operators like ‘+‘,’–‘,’*‘ and ‘/‘ are
left-associative].
• Check especially for a condition when the operator at the top of the stack and the scanned
operator both are ‘^‘. In this condition, the precedence of the scanned operator is higher due
to its right associativity. So it will be pushed into the operator stack.
• In all the other cases when the top of the operator stack is the same as the scanned operator,
then pop the operator from the stack because of left associativity due to which the scanned
operator has less precedence.
• Else, Pop all the operators from the stack which are greater than or equal to in precedence than
that of the scanned operator.
• After doing that Push the scanned operator to the stack. (If you encounter parenthesis while
popping then stop there and push the scanned operator in the stack.)
4. If the scanned character is a ‘(‘, push it to the stack.
5. If the scanned character is a ‘)’, pop the stack and output it until a ‘(‘ is encountered, and discard both
the parenthesis.
6. Repeat steps 2-5 until the infix expression is scanned.
7. Once the scanning is over, Pop the stack and add the operators in the postfix expression until it is not
empty.
8. Finally, print the postfix expression.
Input: A + B * C + D
Output: A B C * + D +
class Conversion
{
}
5.5 Reverse a Stack
The stack is a linear data structure which works on the LIFO concept. LIFO stands for last in first out. In the
stack, the insertion and deletion are possible at one end the end is called the top of the stack. Define two
recursive functions BottomInsertion() and Reverse() to reverse a stack using Python. Define some basic
function of the stack like push(), pop(), show(), empty(), for basic operation like respectively append an item
in stack, remove an item in stack, display the stack, check the given stack is empty or not.
BottomInsertion(): this method append element at the bottom of the stack and BottomInsertion accept
two values as an argument first is stack and the second is elements, this is a recursive method.
Reverse(): the method is reverse elements of the stack, this method accept stack as an argument
Reverse() is also a Recursive() function. Reverse() is invoked BottomInsertion() method for completing the
reverse operation on the stack.
Page | 30
Input: Elements = [1, 2, 3, 4, 5]
Output: Original Stack
5
4
3
2
1
Stack after Reversing
1
2
3
4
5
import java.util.Stack;
class StackClass {
# Write Code Here
}
Page | 31
6. Queue
6.1 Linear Queue
Linear queue is a linear data structure that stores items in First in First out (FIFO) manner. With a queue the
least recently added item is removed first. A good example of queue is any queue of consumers for a
resource where the consumer that came first is served first.
import java.util.Scanner;
Page | 32
Implement a last-in-first-out (LIFO) stack using only two queues. The implemented stack should support all
the functions of a normal stack (push, top, pop, and empty).
• void push(int x) Pushes element x to the top of the stack.
• int pop() Removes the element on the top of the stack and returns it.
• int top() Returns the element on the top of the stack.
• boolean empty() Returns true if the stack is empty, false otherwise.
Input:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
Output:
[null, null, null, 2, 2, false]
import java.util.LinkedList;
import java.util.Queue;
class MyStack
{
# Write Code Here
}
public void push(int x)
{
# Write Code Here
}
}
Page | 33
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
Output:
[null, null, null, 1, 1, false]
import java.util.Stack;
class MyQueue {
Page | 34
• If the queue is not full then, insert an element at the end of the queue.
• deQueue() This function is used to delete an element from the circular queue. In a circular queue, the
element is always deleted from the front position.
• Check whether the queue is Empty.
• If it is empty then display Queue is empty.
• If the queue is not empty, then get the last element and remove it from the
queue.
class CircularQueue {
Page | 35
this.queue = new int[size];
this.front = this.rear = -1;
}
Page | 36
15. rotate(): This function rotates the deque by the number specified in arguments. If the number specified is
negative, rotation occurs to the left. Else rotation is to right.
import java.util.ArrayDeque;
import java.util.Deque;
Page | 37
7. Linked List
7.1 Singly Linked List
A singly linked list is a linear data structure in which the elements are not stored in contiguous memory
locations and each element is connected only to its next element using a pointer.
Node(String data) {
this.data = data;
this.next = null;
}
}
class LinkedList
{
# Write Code Here
}
Page | 38
public void remove_last_node()
{
# Write Code Here
}
{
# Write Code Here
}
Page | 39
Input: head = [1, 2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 0th node.
class ListNode
{
# Write Code Here
}
class ListNode {
# Write Code Here
}
Page | 40
}
public class Solution {
public boolean hasCycle(ListNode head)
{
# Write Code Here
}
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
this.next = null;
}
}
Page | 41
public static void main(String[] args)
{
# Write Code Here
}
class ListNode
{
# Write Code Here
}
public class Solution {
public boolean isPalindrome(ListNode head)
{
# Write Code Here
}
Page | 42
Input: head = [1, 2, 3, 4, 5, 6]
Output: [4, 5, 6]
Explanation: Since the list has two middle nodes with values 3 and 4, we return the second one.
class ListNode
{
# Write Code Here
}
}
public class Solution
{
# Write Code Here
}
ListNode(int val) {
this.val = val;
this.next = null;
}
}
Page | 43
# Write Code Here
}
Page | 44
8. Circular Single Linked List and Doubly Linked List
8.1 Circular Linked List
The circular linked list is a linked list where all nodes are connected to form a circle. In a circular linked list,
the first node and the last node are connected to each other which forms a circle. There is no NULL at the
end.
import java.util.ArrayList;
public class Main{
static class Node{
int data;
Node next;
Node(int data){
this.data = data;
this.next = null;
}
}
static class CircularLinkedList
{
# Write Code Here
}
Node addAfter(int data, int item)
{
# Write Code Here
}
void deleteNode(Node last, int key)
{
# Write Code Here
}
System.
8.2 Doubly Linked List
The A doubly linked list is a type of linked list in which each node consists of 3 components:
Page | 45
Double Linked List Node
import java.util.Scanner;
class Node {
int data;
Node next;
Node prev;
Node(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
class DLinkedList {
Node head;
int ctr;
DLinkedList() {
this.head = null;
this.ctr = 0;
}
Page | 46
}
void deleteBeg()
{
# Write Code Here
}
void deleteEnd()
{
# Write Code Here
}
void traverseF()
{
# Write Code Here
}
void traverseR()
{
# Write Code Here
}
Page | 47
Output: Merged List
class Node {
int data;
Node next, prev;
Node(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
Page | 48
}
Algorithm:
delAllOccurOfGivenKey (head_ref, x)
if head_ref == NULL
return
Initialize current = head_ref
Declare next
while current != NULL
if current->data == x
next = current->next
deleteNode(head_ref, current)
current = next
else
current = current->next
class Node {
int data;
Node next, prev;
Node(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
Page | 49
static Node deleteAllOccurOfX(Node head, int x)
{
# Write Code Here
}
Procedure:
1. Get the pointer to the node at position n by traversing the doubly linked list up to the nth node from
the beginning.
2. Delete the node using the pointer obtained in Step 1.
class Node {
int data;
Node next, prev;
Node(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
Page | 50
static Node deleteNode(Node head, Node del)
{
# Write Code Here
}
Page | 51
9. Trees
9.1 Tree Creation and Basic Tree Terminologies
A tree data structure is a hierarchical structure that is used to represent and organize data in a way that is
easy to navigate and search. It is a collection of nodes that are connected by edges and has a hierarchical
relationship between the nodes.
1. Parent Node: The node which is a predecessor of a node is called the parent node of that node. {B} is
the parent node of {D, E}.
2. Child Node: The node which is the immediate successor of a node is called the child node of that node.
Examples: {D, E} are the child nodes of {B}.
3. Root Node: The topmost node of a tree or the node which does not have any parent node is called the
root node. {A} is the root node of the tree. A non-empty tree must contain exactly one root node and
exactly one path from the root to all other nodes of the tree.
4. Leaf Node or External Node: The nodes which do not have any child nodes are called leaf nodes. {K, L,
M, N, O, P} are the leaf nodes of the tree.
5. Ancestor of a Node: Any predecessor nodes on the path of the root to that node are called Ancestors
of that node. {A, B} are the ancestor nodes of the node {E}
6. Descendant: Any successor node on the path from the leaf node to that node. {E, I} are the
descendants of the node {B}.
7. Sibling: Children of the same parent node are called siblings. {D, E} are called siblings.
8. Level of a node: The count of edges on the path from the root node to that node. The root node has
level 0.
9. Internal node: A node with at least one child is called Internal Node.
10. Neighbour of a Node: Parent or child nodes of that node are called neighbors of that node.
11. Subtree: Any node of the tree along with its descendant.
import java.util.ArrayList;
import java.util.List;
Page | 52
{
# Write Code Here
}
static void printLeafNodes(int root, List<List<Integer>> adj)
{
# Write Code Here
}
static void printDegrees(int root, List<List<Integer>> adj)
{
# Write Code Here
}
public static void main(String[] args)
{
# Write Code Here
}
}
Page | 53
3. Visit the root.
import java.util.Scanner;
class Node
{
# Write Code Here
}
class BT {
Node root;
BT() {
this.root = null;
}
void insert(int data)
{
# Write Code Here
}
Node insertRec(Node root, int data)
{
# Write Code Here
}
void postorder(Node root)
{
# Write Code Here
}
void preorder(Node root)
{
# Write Code Here
}
}
void inorder(Node root)
{
# Write Code Here
}
}
Page | 54
Output:
The idea is to do an iterative level order traversal of the given tree using queue. If we find a node whose
left child is empty, we make a new key as the left child of the node. Else if we find a node whose right child
is empty, we make the new key as the right child. We keep traversing the tree until we find a node whose
either left or right child is empty.
class Node
{
# Write Code Here
}
Page | 55
Recursively calculate the height of the left and the right subtrees of a node and assign height to the node
as max of the heights of two children plus 1.
Procedure:
• Recursively do a Depth-first search.
• If the tree is empty then return 0
• Otherwise, do the following
• Get the max depth of the left subtree recursively i.e. call maxDepth( tree->left-subtree)
• Get the max depth of the right subtree recursively i.e. call maxDepth( tree->right-subtree)
• Get the max of max depths of left and right subtrees and add 1 to it for the current node.
• Return max_depth.
class Node
{
int data;
Node left, right;
Node(int data) {
this.data = data;
this.left = null;
this.right = null;
}
}
Page | 56
Given a binary tree, delete a node from it by making sure that the tree shrinks from the bottom (i.e. the
deleted node is replaced by the bottom-most and rightmost node).
10
/ \
20 30
Output:
30
/
20
Output:
10
/ \
40 30
Algorithm:
1. Starting at the root, find the deepest and rightmost node in the binary tree and the node which we
want to delete.
2. Replace the deepest rightmost node’s data with the node to be deleted.
3. Then delete the deepest rightmost node.
Page | 57
class Node {
int data;
Node left, right;
Node(int data) {
this.data = data;
this.left = null;
this.right = null;
}
}
Page | 58
10. Binary Search Tree (BST)
10.1 Searching in Binary Search Tree
Given a BST, the task is to delete a node in this BST. For searching a value in BST, consider it as a sorted
array. Perform search operation in BST using Binary Search Algorithm.
Page | 59
// Node class to represent each node of the BST
class Node {
int key;
Node left, right;
Page | 60
Output: 8
Output: 10
import java.util.ArrayList;
import java.util.List;
class Node {
int data;
Node left, right;
class BinarySearchTree
{
# Write Code Here
}
1. The left subtree of a node contains only nodes with keys less than the node’s key.
2. The right subtree of a node contains only nodes with keys greater than the node’s key.
3. Both the left and right subtrees must also be binary search trees.
4. Each node (item in the tree) has a distinct key.
Page | 61
Output: Check if max value in left subtree is smaller than the node and min value in right subtree greater
than the node, then print it “Is BST” otherwise “Not a BST”
Procedure:
1. If the current node is null then return true
2. If the value of the left child of the node is greater than or equal to the current node then return false
3. If the value of the right child of the node is less than or equal to the current node then return false
4. If the left subtree or the right subtree is not a BST then return false
5. Else return true
class Node {
int data;
Node left, right;
class BinaryTree
{
# Write Code Here
}
Page | 62
10.4 Second Largest Element in BST
Given a Binary search tree (BST), find the second largest element.
Output: 5
/ \
5 20
30
Output: 20
Procedure: The second largest element is second last element in inorder traversal and second element in
reverse inorder traversal. We traverse given Binary Search Tree in reverse inorder and keep track of counts
of nodes visited. Once the count becomes 2, we print the node.
class Node {
int key;
Node left, right;
class BinarySearchTree
{
# Write Code Here
}
secondLargestUtil(node.right);
count++;
Page | 63
secondLargestUtil(node.left);
}
// Driver code
public static void main(String[] args)
{
# Write Code Here
}
}
Try:
1. Kth largest element in BST when modification to BST is not allowed: Given a Binary Search Tree (BST)
and a positive integer k, find the k’th largest element in the Binary Search Tree. For a given BST, if k = 3,
then output should be 14, and if k = 5, then output should be 10.
Page | 64
Procedure for inserting a value in a BST:
A new key is always inserted at the leaf by maintaining the property of the binary search tree. We start
searching for a key from the root until we hit a leaf node. Once a leaf node is found, the new node is added
as a child of the leaf node. The below steps are followed while we try to insert a node into a binary search
tree:
• Check the value to be inserted (say X) with the value of the current node (say val) we are in:
• If X is less than val move to the left subtree.
• Otherwise, move to the right subtree.
• Once the leaf node is reached, insert X to its right or left based on the relation between X and the leaf
node’s value.
class BinarySearchTree
{
void inorder()
{
inorderRec(root);
}
Page | 65
}
}
// Driver code
public static void main(String[] args)
{
# Write Code Here
}
}
Try:
1. Check if two BSTs contain same set of elements: Given two Binary Search Trees consisting of unique
positive elements, we have to check whether the two BSTs contain the same set of elements or not.
Input: Consider two BSTs which contains same set of elements {5, 10, 12, 15, 20, 25}, but the structure of
the two given BSTs can be different.
Page | 66
11. AVL Tree
11.1 Insertion in an AVL Tree
AVL tree is a self-balancing Binary Search Tree (BST) where the difference between heights of left and right
subtrees cannot be more than one for all nodes. To make sure that the given tree remains AVL after every
insertion, we must augment the standard BST insert operation to perform some re-balancing.
Following are two basic operations that can be performed to balance a BST without violating the BST
property (keys(left) < key(root) < keys(right)).
• Left Rotation
• Right Rotation
T1, T2 and T3 are subtrees of the tree, rooted with y (on the left side) or x (on the right side)
class TreeNode {
int val, height;
TreeNode left, right;
TreeNode(int d) {
val = d;
height = 1;
}
}
class AVL_Tree {
Page | 67
}
TreeNode leftRotate(TreeNode x)
{
# write the code
}
public static void main(String[] args) {
# write the code
}
1. Left Rotation
2. Right Rotation
T1, T2 and T3 are subtrees of the tree rooted with y (on left side)
or x (on right side)
Page | 68
iv. y is right child of z and x is left child of y (Right Left Case)
class TreeNode
{
int val, height;
TreeNode left, right;
TreeNode(int d) {
val = d;
height = 1;
}
}
class AVL_Tree {
TreeNode leftRotate(TreeNode z)
{
# Write code here
}
TreeNode rightRotate(TreeNode z)
{
# Write code here
}
TreeNode(int d) {
key = d;
Page | 69
height = 1;
desc = 0;
}
}
class AVL_Tree
{
# Write code here
}
Input: H = 0
Output: N = 1
Only '1' node is possible if the height
of the tree is '0' which is the root node.
Input: H = 3
Output: N = 7
Recursive approach:
In an AVL tree, we have to maintain the height balance property, i.e. difference in the height of the left
and the right subtrees cannot be other than -1, 0 or 1 for each node.
We will try to create a recurrence relation to find minimum number of nodes for a given height, n(h).
• For height = 0, we can only have a single node in an AVL tree, i.e. n(0) = 1
• For height = 1, we can have a minimum of two nodes in an AVL tree, i.e. n(1) = 2
Page | 70
• Now for any height ‘h’, root will have two subtrees (left and right). Out of which one has to be of
height h-1 and other of h-2. [root node excluded]
• So, n(h) = 1 + n(h-1) + n(h-2) is the required recurrence relation for h>=2 [1 is added for the root
node]
Page | 71
12. Graph Traversal
12.1 Breadth First Search
The Breadth First Search (BFS) algorithm is used to search a graph data structure for a node that meets a
set of criteria. It starts at the root of the graph and visits all nodes at the current depth level before moving
on to the nodes at the next depth level.
For a given graph G, print BFS traversal from a given source vertex.
import java.util.*;
public Graph()
{
graph = new HashMap<>();
}
For a given graph G, print DFS traversal from a given source vertex.
Input: n = 4, e = 6
0 -> 1, 0 -> 2, 1 -> 2, 2 -> 0, 2 -> 3, 3 -> 3
Page | 72
Output: DFS from vertex 1: 1 2 0 3
Explanation:
DFS Diagram:
Input: n = 4, e = 6
2 -> 0, 0 -> 2, 1 -> 2, 0 -> 1, 3 -> 3, 1 -> 3
Explanation:
DFS Diagram:
import java.util.*;
class Graph {
private Map<Integer, List<Integer>> graph;
public Graph() {
// Initialize the graph as a HashMap of ArrayLists
graph = new HashMap<>();
}
public void addEdge(int u, int v)
{
# Write code here
}
DFSUtil(v, visited);
Page | 73
}
public static void main(String[] args)
{
# Write code here
}
}
12.3 Best First Search (Informed Search)
The idea of Best First Search is to use an evaluation function to decide which adjacent is most promising
and then explore. Best First Search falls under the category of Heuristic Search or Informed Search.
Algorithm:
Best-First-Search(Graph g, Node start)
1) Create an empty PriorityQueue
PriorityQueue pq;
2) Insert "start" in pq.
pq.insert(start)
3) Until PriorityQueue is empty
u = PriorityQueue.DeleteMin
If u is the goal
Exit
Else
Foreach neighbor v of u
If v "Unvisited"
Mark v "Visited"
pq.insert(v)
Mark u "Examined"
End procedure
• We start from source “S” and search for goal “I” using given costs and Best First search.
Page | 74
• pq initially contains S
• We remove S from pq and process unvisited neighbors of S to pq.
• pq now contains {A, C, B} (C is put before B because C has lesser cost)
• We remove A from pq and process unvisited neighbors of A to pq.
• pq now contains {C, B, E, D}
• We remove C from pq and process unvisited neighbors of C to pq.
• pq now contains {B, H, E, D}
• We remove B from pq and process unvisited neighbors of B to pq.
• pq now contains {H, E, D, F, G}
• We remove H from pq.
• Since our goal “I” is a neighbor of H, we return.
import java.util.*;
Input: Consider the graph given below where V = 5, E = 4, edges = {(0,1), (0,2), (0,3), (2,4)}
Page | 75
Output: 0 1 2 3 4
Explanation:
0 is connected to 1, 2, and 3.
2 is connected to 4.
So starting from 0, it will go to 1 then 2 then 3. After this 2 to 4, thus BFS will be 0 1 2 3 4.
Input: Consider the graph given below where V = 3, E = 2, edges = {(0, 1), (0, 2)}
Output: 0 1 2
Explanation:
0 is connected to 1, 2. So starting from 0, it will go to 1 then 2, thus BFS will be 0 1 2.
Your task is to complete the function bfsOfGraph() which takes the integer V denoting the number of
vertices and adjacency list as input parameters and returns a list containing the BFS traversal of the graph
starting from the 0th vertex from left to right.
import java.util.*;
class Graph {
private int V;
private LinkedList<Integer>[] adj;
Graph(int v) {
V = v;
adj = new LinkedList[v];
for (int i = 0; i < v; ++i)
adj[i] = new LinkedList();
}
Page | 76
adj[v].add(w);
}
void BFS(int s)
{
# Write Code Here
}
}
Output: 0 1 2 3
public Graph()
{
graph = new HashMap<>();
}
Page | 77
{
# Write Code Here
}
private void DFSUtil(int v, boolean[] visited)
{
# Write Code Here
}
}
Consider a graph G and detect a negative cycle in the graph using Bellman Ford algorithm.
Page | 78
13. Minimum Spanning Tree (MST)
13.1 Kruskal’s Algorithm
In Kruskal’s algorithm, sort all edges of the given graph in increasing order. Then it keeps on adding new
edges and nodes in the MST if the newly added edge does not form a cycle. It picks the minimum weighted
edge at first and the maximum weighted edge at last.
Kruskal’s algorithm to find the minimum cost spanning tree uses the greedy approach. The Greedy Choice
is to pick the smallest weight edge that does not cause a cycle in the MST constructed so far.
Input: For the given graph G find the minimum cost spanning tree.
The graph contains 9 vertices and 14 edges. So, the minimum spanning tree formed will be having (9 – 1)
= 8 edges.
After sorting:
Page | 79
14 3 5
Now pick all edges one by one from the sorted list of edges.
Output:
Page | 80
public static void main(String[] args) {
Graph g = new Graph(4);
g.addEdge(0, 1, 10);
g.addEdge(0, 2, 6);
g.addEdge(0, 3, 5);
g.addEdge(1, 3, 15);
g.addEdge(2, 3, 4);
// Function call
g.KruskalMST();
}
}
Output: Following are the edges in the constructed MST
2 -- 3 == 4
0 -- 3 == 5
0 -- 1 == 10
Minimum Cost Spanning Tree: 19
Prim’s Algorithm:
The working of Prim’s algorithm can be described by using the following steps:
1. Determine an arbitrary vertex as the starting vertex of the MST.
2. Follow steps 3 to 5 till there are vertices that are not included in the MST (known as fringe vertex).
3. Find edges connecting any tree vertex with the fringe vertices.
4. Find the minimum among these edges.
5. Add the chosen edge to the MST if it does not form any cycle.
6. Return the MST and exit
Input: For the given graph G find the minimum cost spanning tree.
Output: The final structure of the MST is as follows and the weight of the edges of the MST is (4 + 8 + 1 +
2 + 4 + 2 + 7 + 9) = 37.
Page | 81
import java.util.Arrays;
}
public static void main(String[] args)
{
# Write Code Here
}
}
Output:
Edge Weight
0-1 2
1-2 3
0-3 6
1-4 5
Page | 82
Laplacian matrix:
A Laplacian matrix L, where L[i, i] is the degree of node i and L[i, j] = −1 if there is an edge between nodes i
and j, and otherwise L[i, j] = 0.
Kirchhoff’s theorem provides a way to calculate the number of spanning trees for a given graph as a
determinant of a special matrix. Consider the following graph,
In order to calculate the number of spanning trees, construct a Laplacian matrix L, where L[i, i] is the degree
of node i and L[i, j] = −1 if there is an edge between nodes i and j, and otherwise L[i, j] = 0.
for the above graph, The Laplacian matrix will look like this
The determinant is always the same, regardless of which row and column we remove from L.
import java.util.Arrays;
Page | 83
void multiply(long[][] A, long[][] B, long[][] C, int size) {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
C[i][j] = 0;
for (int k = 0; k < size; k++) {
C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % MOD;
}
}
}
}
void power(long[][] A, int N, long[][] result, int size)
{
# Write Code Here
}
Input:
Output: Minimum Product that we can obtain is 180 for above graph by choosing edges 0-1, 1-2, 0-3 and
1-4
This problem can be solved using standard minimum spanning tree algorithms like Kruskal and prim’s
algorithm, but we need to modify our graph to use these algorithms. Minimum spanning tree algorithms
Page | 84
tries to minimize the total sum of weights, here we need to minimize the total product of weights. We can
use the property of logarithms to overcome this problem.
log(w1* w2 * w3 * …. * wN) = log(w1) + log(w2) + log(w3) ….. + log(wN)
We can replace each weight of the graph by its log value, then we apply any minimum spanning tree
algorithm which will try to minimize the sum of log(wi) which in turn minimizes the weight product.
import java.util.Arrays;
// A utility function to find the vertex with minimum key value, from the set of
// vertices not yet included in MST
int minKey(int key[], boolean mstSet[]) {
int min = Integer.MAX_VALUE, min_index = -1;
return min_index;
}
Algorithm:
1. Sort all edges of graph in non-increasing order of edge weights.
Page | 85
2. Initialize MST as original graph and remove extra edges using step 3.
3. Pick highest weight edge from remaining edges and check if deleting the edge disconnects the
graph or not.
If disconnects, then we don’t delete the edge.
Else we delete the edge and continue.
If we delete highest weight edge of weight 14, graph doesn’t become disconnected, so we remove it.
Page | 86
Next is 9. We cannot delete 9 as deleting it causes disconnection.
import java.util.ArrayList;
import java.util.Collections;
Page | 87
}
Input: N = 4, E = 6
Output: Yes
Explanation: The diagram clearly shows a cycle 0 -> 2 -> 0
Page | 88
14. Final Notes
The only way to learn programming is program, program and program on challenging problems. The
problems in this tutorial are certainly NOT challenging. There are tens of thousands of challenging problems
available – used in training for various programming contests (such as International Collegiate Programming
Contest (ICPC), International Olympiad in Informatics (IOI)). Check out these sites:
• The ACM - ICPC International collegiate programming contest (https://icpc.global/ )
• The Topcoder Open (TCO) annual programming and design contest (https://www.topcoder.com/ )
• Universidad de Valladolid’s online judge (https://uva.onlinejudge.org/ ).
• Peking University’s online judge (http://poj.org/ ).
• USA Computing Olympiad (USACO) Training Program @ http://train.usaco.org/usacogate.
• Google’s coding competitions (https://codingcompetitions.withgoogle.com/codejam,
https://codingcompetitions.withgoogle.com/hashcode )
• The ICFP programming contest (https://www.icfpconference.org/ )
• BME International 24-hours programming contest (https://www.challenge24.org/ )
• The International Obfuscated C Code Contest (https://www0.us.ioccc.org/main.html )
• Internet Problem Solving Contest (https://ipsc.ksp.sk/ )
• Microsoft Imagine Cup (https://imaginecup.microsoft.com/en-us )
• Hewlett Packard Enterprise (HPE) Codewars (https://hpecodewars.org/ )
• OpenChallenge (https://www.openchallenge.org/ )
Page | 89
V. TEXT BOOKS:
1. Rance D. Necaise, “Data Structures and Algorithms using Python”, Wiley Student Edition.
2. Benjamin Baka, David Julian, “Python Data Structures and Algorithms”, Packt Publishers, 2017.
VI. REFERENCE BOOKS:
1. S. Lipschutz, “Data Structures”, Tata McGraw Hill Education, 1st Edition, 2008.
2. D. Samanta, “Classic Data Structures”, PHI Learning, 2nd Edition, 2004.
VII. ELECTRONICS RESOURCES:
1. https://www.tutorialspoint.com/data_structures_algorithms/algorithms_basics.htm
2. https://www.codechef.com/certification/data-structures-and-algorithms/prepare
3. https://www.cs.auckland.ac.nz/software/AlgAnim/dsToC.html
4. https://online-learning.harvard.edu/course/data-structures-and-algorithms
VIII. MATERIALS ONLINE
1. Syllabus
2. Lab manual
Page | 90