DSA Graphs: DFS, BFS, and MST Algorithms
DSA Graphs: DFS, BFS, and MST Algorithms
Graphs: Graph Abstract Data Type, Elementary Graph operations (DFS and BFS), Minimum
Cost Spanning Trees (Prim ‘s and Kruskal ‘s Algorithms).
Sorting and Searching: Insertion sort, Quick sort, Best computing time for Sorting, Merge
sort, Heap sort, Shell sort, Sorting on Several Keys, List and Table Sorts, Summary of Internal
Sorting, Linear and Binary Search algorithms
==========================================================================
Graph Definition
Graph consists of a finite set of vertices and set of Edges or Links which connect to a pair of
nodes.
A Graph is a non-linear data structure of nodes and edges.
Trees Graphs
1 Only one path | edge between two Multiple paths | edges | links among two
nodes. nodes.
2 Has a root node No root node
3 Don’t have loops Can have loops
4 If graph has N nodes, N-1 edges No of edges not defined
5 Hierarchical Model Network Model
Graph
Tree
16 16
54 19
54 19
67 32
67 87
87
A tree is an undirected graph.
Undirected Graph
In an undirected graph the edges are bidirectional with no direction associated with them.
Hence, the graph can be traversed in either direction. The absence of an arrow tells us that
the graph is undirected.
16 16
54 19 54 19
32 32
67
67
87 87
Unweighted Graph
An unweighted graph is a graph in which all edges | paths are considered to have
same weight.
Weighted Graph
A weighted graph is graph in which each branch is given a numerical weight.
H Adjacency List
A: B,D
B: C,F
C: E,G,H
A B C G D: F
E: F,B
F: A
D F E G: E,H
H: A
Solution. The equivalent search tree for the above graph is as follows. As DFS traverses the
tree “deepest node first”, it would always pick the deeper branch until it reaches the solution
or it runs out of nodes and goes to the next branch. The traversal is shown in blue arrows.
Path: A→B→C→E→F→D→G→H
= the depth of the search tree = the number of levels of the search tree.
= number of nodes in level .
Time complexity: Equivalent to the number of nodes traversed in DFS
Completeness: DFS is complete if the search tree is finite, meaning for a given finite search
tree, DFS will come up with a solution if it exists.
Optimality: DFS is not optimal, meaning the number of steps in reaching the solution, or the
cost spent in reaching it is high.
Adjacency List
A B C G A: B,D
B: C,F
C: E,G,H
D F E D: F
E: F,B
F: A
G: E,H
Breadth-First Search (BFS) is a graph traversal algorithm that explores all the vertices of
a graph layer by layer. It starts from a source vertex and explores all its neighbors before
moving to the next level of neighbors.
Algorithm
1. Initialize:
Create a queue and enqueue the starting vertex.
Mark the starting vertex as visited.
2. Process the Queue:
Dequeue a vertex from the queue.
For each unvisited adjacent vertex of the dequeued vertex:
Mark it as visited.
Enqueue it.
BFS Order: A → B → D→ C → F → E → G
Time complexity: Equivalent to the number of nodes traversed in BFS until the shallowest
solution.
Completeness: BFS is complete, meaning for a given search tree, BFS will come up with a
solution if it exists.
Optimality: BFS is optimal as long as the costs of all edges are equal.
A C Program that makes traversal methods for BFS and DFS from a given source
vertex.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n, i, j, start;
printf("Enter the number of vertices: ");
scanf("%d", &n);
printf("Enter the adjacency matrix:\n");
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
scanf("%d", &graph[i][j]);
}
}
printf("Enter the starting vertex: ");
scanf("%d", &start);
printf("BFS Traversal: ");
for (i = 1; i <= n; i++)
{
visited[i] = 0;
}
bfs(start, n);
printf("\nDFS Traversal: ");
for (i = 1; i <= n; i++)
{
visited[i] = 0;
}
dfs(start, n);
return 0;
}
/*INPUT
Enter the number of vertices and edges: 6 7
Enter edge (u v): 1 2
Enter edge (u v): 1 3
Enter edge (u v): 1 4km,
Enter edge (u v): 2 5
Enter edge (u v): 4 6
Enter edge (u v): 5 6
DSA UNIT 5 MRS. MADHAVI
Enter edge (u v): 3 4
Enter the starting vertex: 1
Enter the starting vertex: 1
OUTPUT
BFS Traversal: 1 2 3 4 5 6
DFS Traversal: 1 2 5 3 4 6
5
A E
1 10
7 2
B C D
3 4
Step 2 - Add the edge DE with weight 2 to the MST as it is not creating the cycle.
Step 3 - Add the edge BC with weight 3 to the MST, as it is not creating any cycle or loop.
Step 4 - Now, pick the edge CD with weight 4 to the MST, as it is not forming the cycle.
Step 5 - After that, pick the edge AE with weight 5. Including this edge will create the
cycle, so discard it.
Step 6 - Pick the edge AC with weight 7. Including this edge will create the cycle, so discard
it.
#include <stdio.h>
#include <stdlib.h>
struct Edge
{
int src, dest, weight;
};
struct Graph
{
int V, E;
struct Edge edges[MAX];
};
int main()
{
struct Graph graph;
int i;
printf("Enter the number of vertices: ");
scanf("%d", &graph.V);
printf("Enter the number of edges: ");
scanf("%d", &graph.E);
printf("Enter the edges in the format (src dest weight):\n");
for (i = 0; i < graph.E; i++)
scanf("%d %d %d", &[Link][i].src, &[Link][i].dest, &[Link][i].weight);
kruskalMST(&graph);
return 0;
}
/* Input
Enter the number of vertices: 4
Enter the number of edges: 5
Enter the edges in the format (src dest weight):
0 1 10
026
035
1 3 15
234
Continue adding the smallest edge until all vertices are included in the MST.
4. Output:
The MST, which includes all vertices and the minimum total weight.
Example: Construct the minimum spanning tree (MST) for the given graph using Prim’s
Algorithm-
The above discussed steps are followed to find the minimum cost spanning tree using
Prim’s Algorithm-
STEP 1
Step 2
Step 4
Step 5
Step 6
Since all the vertices have been included in the MST, so we stop.
#include <stdio.h>
#include <limits.h>
#define V 5
int main()
{
int i,j,graph[V][V];
printf("Enter the adjacency matrix of the graph (%d x %d):\n", V, V);
for (i = 0; i < V; i++)
{
for (j = 0; j < V; j++)
{
scanf("%d", &graph[i][j]);
}
}
primMST(graph);
return 0;
}
/*Input
02060
20385
03007
68009
05790
Output
Edge Weight
0-1 2
1-2 3
0-3 6
1-4 5
#include <stdio.h>
int main()
{
int n, i;
int arr[n];
printf("Enter %d elements:", n);
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
DSA UNIT 5 MRS. MADHAVI
insertionSort(arr, n);
return 0;
}
Input
Enter the number of elements: 7
Enter 7 elements:88 11 99 22 55 33 44
OUTPUT
Sorted array: 11 22 33 44 55 88 99
QUICK Sort
Algorithm
1. Choose a Pivot
Select an element as the pivot (commonly the last element, the first element, or
a random element).
2. Partition the Arra
Rearrange the array so that:
Elements smaller than the pivot are on the left.
Elements larger than the pivot are on the right.
o The pivot is now in its correct position.
3. Recursively Sort:
o Apply the same steps to the subarrays on the left and right of the pivot.
2. Partition:
Rearrange the array so elements smaller than 2 are to the left, and larger elements
are to the right.
0,1,2,8,7,10,3
Pivot 2 is now in its correct position.
3. Recursively Sort:
o Left Subarray: 0,1
o Right Subarray: 8,7,10,3
6. Combine:
o Final sorted array: 0,1,2,3,7,8,10
#include <stdio.h>
Input
Enter number of elements: 6
Enter the elements: 88 66 44 11 55 22
OUTPUT
Sorted elements: 11 22 44 55 66 88
2. Insertion Sort
Best Case Time Complexity: O(n)
Occurs when the array is already sorted.
The algorithm iterates through the array but does not perform any shifts or swaps
[Link] Sort
Best Case Time Complexity: O(n2)
Selection Sort always requires n−1 comparisons for the first element, n−2 for the
second, and so on, regardless of the input's order.
4. Merge Sort
Best Case Time Complexity: O(nlogn)
Merge Sort always divides the array into halves and merges them in O(n), so its best,
worst, and average case time complexities are O(nlogn).
5. Quick Sort
Best Case Time Complexity: O(nlogn)
Occurs when the pivot divides the array into two equal halves at each step.
Requires fewer recursive calls and fewer comparisons.
6. Heap Sort
Best Case Time Complexity: O(nlogn)
Heap Sort always builds a heap and extracts elements, so its time complexity does not
depend on input order.
7. Counting Sort, Radix Sort, Bucket Sort
These are non-comparison-based algorithms and can achieve:
o Best Case Time Complexity: O(n)
o Applicable only when specific conditions (like integer keys or small ranges) are
met.
Algorithm Best Case Average Case Worst Case
Algorithm Steps
1. Divide:
Divide the array into two halves.
2. Conquer:
Recursively apply merge sort to the two halves until each subarray contains a
single element (base case).
3. Combine:
Merge the two sorted halves into a single sorted array.
i = 0; j = 0; k = left;
int main()
{
int n, i;
printf("Enter number of elements: ");
scanf("%d", &n);
int arr[n];
printf("Enter the elements: ");
for (i = 0; i < n; i++) { scanf("%d", &arr[i]); }
mergeSort(arr, 0, n - 1);
printf("Sorted elements: ");
for (i = 0; i < n; i++) { printf("%d ", arr[i]); }
return 0;
}
Input
Enter number of elements: 6
Enter the elements: 88 66 44 11 55 22
OUTPUT
Sorted elements: 11 22 44 55 66 88
HEAP Sort
Heap Sort is a comparison-based sorting algorithm that uses the properties of a
binary heap data structure to sort elements.
It is an in-place, unstable sorting algorithm that efficiently sorts an array by
repeatedly building a heap and extracting the largest or smallest element.
Binary Heap
Heap Property:
The largest or smallest element is always at the root of the heap.
Heapify Operation:
Ensures that the heap property is maintained in a subtree.
Algorithm Steps
1. Build a Max-Heap
Convert the input array into a max-heap using the heapify operation.
2. Sort the Array
Swap the root (largest element) with the last element.
Reduce the heap size by 1.
Apply heapify to restore the heap property.
Repeat until the heap size is reduced to 1.
int main()
{
int i, n, arr[n];
printf("Enter number of elements: ");
scanf("%d", &n);
heapSort(arr, n);
printf("Sorted elements: ");
for (i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
INPUT
Enter number of elements: 8
Enter the elements: 22 99 77 66 11 55 33 44
OUTPUT
Sorted elements: 11 22 33 44 55 66 77 99
Algorithm
1. Initialize Gap
Start with a gap size larger than 1 (e.g., half the array size).
2. Sort with Gap
Perform a gapped version of insertion sort for the current gap size.
3. Reduce Gap
Divide the gap size (commonly by 2 or other predefined methods).
4. Repeat
Continue until the gap size is 1, at which point the array is sorted.
1. Initial Gap:
Gap = ⌊n/2⌋=2.
Sort elements separated by a gap of 2:
Compare 12 and 54 (no swap needed).
Compare 3 and 2: Swap.
12,2,54,34,3
Compare 54 and 3: Swap.
12,2,3,34,54
2. Reduce Gap:
Gap = ⌊2/2⌋=1.
Perform a regular insertion sort:
Compare adjacent elements and sort: 2,3,12,34,54
3. Final Sorted Array: 2,3,12,34,54
int main()
{
int i, n;
printf("Enter number of elements: ");
scanf("%d", &n);
int arr[n];
printf("Enter the elements: ");
for (i = 0; i < n; i++)
scanf("%d", &arr[i]);
shellSort(arr, n);
printf("Sorted elements: ");
for (i = 0; i < n; i++)
printf("%d ", arr[i]);
return 0;
}
INPUT
Enter number of elements: 3
Enter the elements: 11 55 22
OUTPUT
Sorted elements: 11 22 55
Linear Search
Linear Search is a simple and straightforward algorithm used to search for an element in a
list or array.
It works by sequentially checking each element in the array until the target element is
found or the entire array is traversed.
Algorithm
For an array arr of size n and a target element x:
1. Start a loop from index i = 0 to i < n.
2. Check if arr[i] == x.
3. If true, return i.
4. If the loop ends without finding the element, return -1.
Example Input
Array: 5,8,3,6,1
search: 6
Process:
1. Compare 5 with 6 → Not a match.
2. Compare 8 with 6 → Not a match.
3. Compare 3 with 6 → Not a match.
4. Compare 6 with 6 → Match found.
int main()
{
int arr[] = {5, 8, 3, 6, 1};
int n = sizeof(arr) / sizeof(arr[0]);
int target = 6;
return 0;
}
OUTPUT
Element found at index 3
Binary Search
Binary Search is an efficient algorithm used to find the position of a target element in a sorted
array. Unlike Linear Search, which checks each element one by one, Binary Search divides
the search space in half at each step, making it significantly faster.
Algorithm
For a sorted array arr of size n and target x:
1. Initialize low = 0 and high = n - 1.
2. While low <= high:
Compute mid = low + (high - low) / 2.
If arr[mid] == x, return mid.
If arr[mid] > x, update high = mid - 1.
If arr[mid] < x, update low = mid + 1.
3. If the loop exits, return -1 (target not found).
Disadvantages
1. Requires Sorting
o Only works on sorted data, so the array must be sorted beforehand.
2. Not Optimal for Small Arrays
o For small datasets, the overhead of calculating the middle index may not be
worth it.
if (arr[mid] == key)
{
printf("Element found at index %d\n", mid);
return;
}
else if (arr[mid] < key)
left = mid + 1;
else
right = mid - 1;
}
int main()
{
int size, key;
int arr[size];
return 0;
}
OUTPUT
Enter the number of elements: 9
Enter 9 elements in sorted order: 11 22 33 44 55 66 77 88 99
Enter the element to search: 77
Element found at index 6
ooo000ooo