Avl Tree Merged
Avl Tree Merged
Description:-
Adelson-Velskii and Landis are the people who discovered it, so the name came from their names i.e., AVL. It is commonly referred to as a hei ght binary tree.
An AVL tree is one that has one of the following characteristics at each of its nodes.
If a node's longest path in its left subtree is longer than its longest path in its right subtree, the node is said to be "left heavy."
If the longest path in a node's right subtree is one more long than the longest path in its left subtree, the node is said to be "right heavy."
If the longest paths in the right and left subtrees are equal, a node is said to be balanced.
LL Rotation: When a new node is added as the left child of the unbalanced node's left subtree.
RR Rotation: When a new node is added as the right child of the right subtree of an unbalanced node, this process is known as RR Rotation.
LR Rotation: When a new node is added as the left child of an unbalanced node's right subtree.
RL Rotation: When a new node is added as the right child of an unbalanced node's left subtree.
Program:-
/*
* AVL Tree Program in C
*/
#include<stdio.h>
#include<stdlib.h>
// function prototyping
struct node* create(int);
struct node* insert(struct node*, int);
struct node* delete(struct node*, int);
struct node* search(struct node*, int);
struct node* rotate_left(struct node*);
struct node* rotate_right(struct node*);
int balance_factor(struct node*);
int height(struct node*);
void inorder(struct node*);
void preorder(struct node*);
void postorder(struct node*);
int main()
{
int user_choice, data;
char user_continue = 'y';
struct node* result = NULL;
switch(user_choice)
{
case 1:
printf("\nEnter data: ");
scanf("%d", &data);
root = insert(root, data);
break;
case 2:
printf("\nEnter data: ");
scanf("%d", &data);
root = delete(root, data);
break;
case 3:
printf("\nEnter data: ");
scanf("%d", &data);
result = search(root, data);
if (result == NULL)
{
printf("\nNode not found!");
}
else
{
printf("\n Node found");
}
break;
case 4:
inorder(root);
break;
case 5:
preorder(root);
break;
case 6:
postorder(root);
break;
case 7:
printf("\n\tProgram Terminated\n");
return 1;
default:
printf("\n\tInvalid Choice\n");
}
return 0;
}
if (root == NULL)
{
return NULL;
}
if (x > root->data)
{
root->right = delete(root->right, x);
if (balance_factor(root) == 2)
{
if (balance_factor(root->left) >= 0)
{
root = rotate_right(root);
}
else
{
root->left = rotate_left(root->left);
root = rotate_right(root);
}
}
}
else if (x < root->data)
{
root->left = delete(root->left, x);
if (balance_factor(root) == -2)
{
if (balance_factor(root->right) <= 0)
{
root = rotate_left(root);
}
else
{
root->right = rotate_right(root->right);
root = rotate_left(root);
}
}
}
else
{
if (root->right != NULL)
{
temp = root->right;
while (temp->left != NULL)
temp = temp->left;
root->data = temp->data;
root->right = delete(root->right, temp->data);
if (balance_factor(root) == 2)
{
if (balance_factor(root->left) >= 0)
{
root = rotate_right(root);
}
else
{
root->left = rotate_left(root->left);
root = rotate_right(root);
}
}
}
else
{
return (root->left);
}
}
root->ht = height(root);
return (root);
}
if(root->data == key)
{
return root;
}
inorder(root->left);
printf("%d ", root->data);
inorder(root->right);
}
postorder(root->left);
postorder(root->right);
printf("%d ", root->data);
}
/*
Sample output:-
------- AVL TREE --------
1. Insert
2. Delete
3. Search
4. Inorder
5. Preorder
6. Postorder
7. EXIT
Enter Your Choice: 1
Enter data: 2
Do you want to continue? y
Node found
Result:-
AVL tree for a given set of elements which are stored in a file. And implement insert and delete
operation on the constructed tree. Write contents of tree into a new file using in-order is successfully
executed.
AIM:- Construct B-Tree an order of 5 with a set of 100 random elements stored in array.
Implement searching, insertion and deletion operations.
Description:-
B-tree is a special type of self-balancing search tree in which each node can contain more than one key
and can have more than two children. It is a generalized form of the binary search tree. It is also known
as a height-balanced m-way tree.
Program:-
// Searching a key on a B-tree in C
#include <stdio.h>
#include <stdlib.h>
#define MAX 3
#define MIN 2
struct BTreeNode {
};
// Create a node
newNode->val[1] = val;
newNode->count = 1;
newNode->link[0] = root;
newNode->link[1] = child;
return newNode;
}
// Insert node
int j = node->count;
node->val[j + 1] = node->val[j];
node->link[j + 1] = node->link[j];
j--;
node->val[j + 1] = val;
node->link[j + 1] = child;
node->count++;
// Split node
void splitNode(int val, int *pval, int pos, struct BTreeNode *node,
int median, j;
median = MIN + 1;
else
median = MIN;
j = median + 1;
j++;
node->count = median;
} else {
*pval = node->val[node->count];
(*newNode)->link[0] = node->link[node->count];
node->count--;
int pos;
if (!node) {
*pval = val;
*child = NULL;
return 1;
} else {
if (val == node->val[pos]) {
return 0;
} else {
return 1;
return 0;
int flag, i;
if (flag)
// Search node
if (!myNode) {
return;
*pos = 0;
} else {
if (val == myNode->val[*pos]) {
return;
return;
}
// Traverse then nodes
int i;
if (myNode) {
traversal(myNode->link[i]);
traversal(myNode->link[i]);
int main() {
insert(8);
insert(9);
insert(10);
insert(11);
insert(15);
insert(16);
insert(17);
insert(18);
insert(20);
insert(23);
traversal(root);
printf("\n");
search(11, &ch, root);
OUTPUT:-
8 9 10 11 15 16 17 18 20 23
11 is found
Description:- A heap is a data structure like a tree with some special properties. The basic requirement
of the heap is that the value of a node must be greater than equal to (or smaller than equal to) the value
of its children and the tree should be a complete binary tree.
Program:-
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int size;
int arr[MAX];
} Heap;
*a = *b;
*b = temp;
int smallest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
smallest = left;
smallest = right;
if (smallest != i) {
swap(&heap->arr[i], &heap->arr[smallest]);
minHeapify(heap, smallest);
}
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
largest = left;
largest = right;
if (largest != i) {
swap(&heap->arr[i], &heap->arr[largest]);
maxHeapify(heap, largest);
if (heap->size == MAX) {
printf("Heap is full\n");
return;
heap->size++;
int i = heap->size - 1;
heap->arr[i] = key;
i = (i - 1) / 2;
}
void insertMaxHeap(Heap *heap, int key) {
if (heap->size == MAX) {
printf("Heap is full\n");
return;
heap->size++;
int i = heap->size - 1;
heap->arr[i] = key;
i = (i - 1) / 2;
int i;
if (heap->arr[i] == key)
break;
if (i == heap->size) {
return -1;
heap->size--;
heapify(heap, i);
return 0;
printf("\n");
int main() {
insertMinHeap(&minHeap, 3);
insertMinHeap(&minHeap, 1);
insertMinHeap(&minHeap, 6);
insertMinHeap(&minHeap, 5);
insertMinHeap(&minHeap, 9);
insertMinHeap(&minHeap, 8);
insertMaxHeap(&maxHeap, 3);
insertMaxHeap(&maxHeap, 1);
insertMaxHeap(&maxHeap, 6);
insertMaxHeap(&maxHeap, 5);
insertMaxHeap(&maxHeap, 9);
insertMaxHeap(&maxHeap, 8);
displayHeap(&minHeap);
displayHeap(&maxHeap);
deleteElement(&minHeap, 5, minHeapify);
deleteElement(&maxHeap, 5, maxHeapify);
displayHeap(&minHeap);
displayHeap(&maxHeap);
return 0;
Output:-
Min Heap: 1 3 6 5 9 8
Max Heap: 9 8 6 1 5 3
Implement BFT and DFT for given graph, when graph is represented by
Descrition:-
Breadth-First Traversal (BFT), also known as Breadth-First Search (BFS), is an algorithm for
traversing or searching tree or graph data structures. It starts at a given node (often called the 'root' in
the context of trees or the 'starting vertex' in graphs) and explores all its neighboring nodes at the
present depth level before moving on to nodes at the next depth level.
Depth-First Traversal (DFT), also known as Depth-First Search (DFS), is an algorithm for
traversing or searching tree or graph data structures. It starts at a given node and explores as far as
possible along each branch before backtracking.
a) Adjacency Matrix
BFT:-
Program
#include <stdio.h>
#include <stdlib.h>
int currentNode;
queue[++rear] = start;
visited[start] = 1;
currentNode = queue[front++];
visited[i] = 1;
int main() {
scanf("%d", &n);
scanf("%d", &graph[i][j]);
scanf("%d", &start);
BFT(graph, n, start);
return 0;
OUTPUT:-
01100
10110
11001
01000
00100
Result:-
This code implements Breadth-First Traversal for a graph represented by adjacency matrix.
DFT:-
Program:-
#include <stdio.h>
#include <stdlib.h>
visited[v] = 1;
DFTUtil(graph, n, i, visited);
int main() {
scanf("%d", &n);
scanf("%d", &graph[i][j]);
scanf("%d", &start);
DFT(graph, n, start);
return 0;
OUTPUT:-
01100
10110
11001
01000
00100
Result:-
This code implements Depth-First Traversal for a graph represented by adjacency matrix.
b) Adjacency Lists
BFT Program:-
#include <stdio.h>
#include <stdlib.h>
int vertex;
} Node;
int numVertices;
Node** adjLists;
} Graph;
int items[MAX];
int front;
int rear;
} Queue;
Node* createNode(int v) {
newNode->vertex = v;
newNode->next = NULL;
return newNode;
graph->numVertices = vertices;
graph->adjLists[i] = NULL;
return graph;
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
newNode = createNode(src);
newNode->next = graph->adjLists[dest];
graph->adjLists[dest] = newNode;
Queue* createQueue() {
Queue* q = malloc(sizeof(Queue));
q->front = -1;
q->rear = -1;
return q;
int isEmpty(Queue* q) {
printf("\nQueue is full!");
} else {
if (q->front == -1)
q->front = 0;
q->rear++;
q->items[q->rear] = value;
int dequeue(Queue* q) {
int item;
if (isEmpty(q)) {
printf("\nQueue is empty!");
item = -1;
} else {
item = q->items[q->front];
q->front++;
return item;
Queue* q = createQueue();
visited[i] = 0;
visited[startVertex] = 1;
enqueue(q, startVertex);
while (!isEmpty(q)) {
while (temp) {
if (!visited[adjVertex]) {
visited[adjVertex] = 1;
enqueue(q, adjVertex);
temp = temp->next;
free(visited);
int main() {
scanf("%d", &vertices);
scanf("%d", &edges);
BFT(graph, start);
printf("\n");
return 0;
OUTPUT:-
Result:-
This code implements Breadth-First Traversal for a graph represented by adjacency lists. .
DFT Program;-
#include <stdio.h>
#include <stdlib.h>
int vertex;
} Node;
Node** adjLists;
} Graph;
Node* createNode(int v) {
newNode->vertex = v;
newNode->next = NULL;
return newNode;
graph->numVertices = vertices;
graph->adjLists[i] = NULL;
return graph;
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
newNode = createNode(src);
newNode->next = graph->adjLists[dest];
graph->adjLists[dest] = newNode;
while (temp) {
if (!visited[adjVertex]) {
temp = temp->next;
visited[i] = 0;
free(visited);
int main() {
scanf("%d", &vertices);
scanf("%d", &edges);
scanf("%d", &start);
DFT(graph, start);
printf("\n");
return 0;
OUTPUT:-
Result:-
This code implements Depth-First Traversal for a graph represented by adjacency lists.
AIM:-Write a program for finding the biconnected components in a given graph.
Description:-
A biconnected component (BCC) of a graph is a maximal subgraph such that the removal of any single
vertex does not disconnect the subgraph. In other words, a biconnected component is a connected
subgraph in which every vertex is on at least one simple cycle. If a vertex is in more than one BCC, it is
called an articulation point or cut vertex.
Program:-
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int vertex;
} Node;
// Graph structure
int numVertices;
Node** adjLists;
int* visited;
} Graph;
// Stack structure
int top;
int capacity;
} Stack;
Node* createNode(int v) {
newNode->vertex = v;
newNode->next = NULL;
return newNode;
graph->numVertices = vertices;
graph->adjLists[i] = NULL;
graph->visited[i] = 0;
graph->disc[i] = -1;
graph->low[i] = -1;
graph->parent[i] = -1;
return graph;
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
newNode = createNode(src);
newNode->next = graph->adjLists[dest];
graph->adjLists[dest] = newNode;
stack->top = -1;
stack->capacity = capacity;
return stack;
// Stack operations
stack->data[++stack->top] = item;
}
int pop(Stack* stack) {
return stack->data[stack->top--];
graph->visited[u] = 1;
int children = 0;
while (temp) {
int v = temp->vertex;
if (!graph->visited[v]) {
children++;
graph->parent[v] = u;
pop(stack);
pop(stack);
temp = temp->next;
int time = 0;
if (!graph->visited[i]) {
if (!isEmpty(stack)) {
pop(stack);
printf("\n");
free(stack->data);
free(stack);
// Main function
int main() {
scanf("%d", &vertices);
scanf("%d", &edges);
findBCC(graph);
while (temp) {
free(temp);
temp = next;
free(graph->adjLists);
free(graph->visited);
free(graph->disc);
free(graph->low);
free(graph->parent);
free(graph);
return 0;
OUTPUT:-
Result:-
This program effectively identifies and prints the biconnected components in the given graph using
Tarjan's algorithm
AIM:-Implement Quick sort and Merge sort and observe the execution time for various input sizes
(Average, Worst and Best cases).
Quick sort:-
Description:-
Quick Sort is a widely used and efficient sorting algorithm based on the divide-and-conquer strategy. It
is known for its average-case time complexity of O(n logn), though its worst-case time complexity is
O(n^2). Quick Sort is often preferred for its speed and efficiency in practice, despite the potential for
worst-case scenarios.
Program:-
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
*a = *b;
*b = temp;
int i = low - 1;
i++;
swap(&arr[i], &arr[j]);
}
}
return (i + 1);
quickSort(arr, pi + 1, high);
arr[i] = i;
arr[i] = n - i;
// Copy an array
dest[i] = source[i];
int main() {
int n = sizes[i];
generateRandomArray(arr, n);
quickSort(arrCopy, 0, n - 1);
generateSortedArray(arr, n);
start = clock();
quickSort(arrCopy, 0, n - 1);
end = clock();
generateReversedArray(arr, n);
start = clock();
quickSort(arrCopy, 0, n - 1);
end = clock();
free(arr);
free(arrCopy);
return 0;
OUTPUT:-
Result:-
Average Case: Quick Sort generally performs well with average time complexity of O(n
logn). The times should increase logarithmically with the size of the input.
Worst Case: Quick Sort’s time complexity in the worst case is O(n^2). You should observe a
sharper increase in time for larger input sizes in this case.
Best Case: The best case (sorted input) also has a time complexity of O(n log n) but usually
performs better due to the nature of the input.
Merge sort:
Description:
Merge Sort is a classic and efficient sorting algorithm that employs the divide-and-conquer
strategy. It is known for its consistent time complexity of O(n log n) for all cases (average, worst,
and best), making it a reliable choice for sorting large datasets.
Program:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
i = 0;
j = 0;
k = l;
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
k++;
arr[k] = L[i];
i++;
k++;
arr[k] = R[j];
j++;
k++;
free(L);
free(R);
if (l < r) {
int m = l + (r - l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
arr[i] = i;
arr[i] = n - i;
// Copy an array
dest[i] = source[i];
int main() {
int n = sizes[i];
generateRandomArray(arr, n);
mergeSort(arrCopy, 0, n - 1);
generateSortedArray(arr, n);
start = clock();
mergeSort(arrCopy, 0, n - 1);
end = clock();
generateReversedArray(arr, n);
start = clock();
mergeSort(arrCopy, 0, n - 1);
end = clock();
printf("%d\t%f\t%f\t%f\n",n,mergeSortAvgTime,mergeSortWorstTime,mergeSortBestTime);
free(arr);
free(arrCopy);
return 0;
Output:-
Result:-
Merge Sort Performance: The execution times should be fairly consistent across different
cases, as Merge Sort has a time complexity of O(n log n) for all cases.
Time Complexity: Compare how the execution time grows with input size. The time complexity
should reflect O(n log n) for different cases.
AIM:-Compare the performance of Single Source Shortest Paths using Greedy method when the graph is
represented by adjacency matrix and adjacency lists
Description:-
In the Single Source Shortest Path (SSSP) problem, we aim to find the shortest path from a source node
to all other nodes in a graph. One of the most common algorithms to solve this problem is Dijkstra's
algorithm, which uses a Greedy approach. Dijkstra's algorithm can be implemented using either an
Adjacency Matrix or Adjacency List to represent the graph, and the choice between these
representations affects the performance of the algorithm significantly.
Program:
#include <stdio.h>
#include <limits.h>
#define V 5
min = dist[v];
min_index = v;
return min_index;
int dist[V];
int sptSet[V];
dist[i] = INF;
sptSet[i] = 0;
dist[src] = 0;
sptSet[u] = 1;
int main() {
dijkstraMatrix(graph, 0);
return 0;
OUTPUT:-
0 0
1 10
2 60
3 30
4 70
Program-2
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define V 5
#define INF INT_MAX
int dest;
int weight;
} Node;
Node* head[V];
} Graph;
Node* n = (Node*)malloc(sizeof(Node));
n->dest = dest;
n->weight = weight;
n->next = NULL;
return n;
Graph* createGraph() {
graph->head[i] = NULL;
return graph;
graph->head[src] = n;
n->next = graph->head[dest];
graph->head[dest] = n;
min = dist[v];
min_index = v;
return min_index;
int dist[V];
int sptSet[V];
dist[i] = INF;
sptSet[i] = 0;
dist[src] = 0;
sptSet[u] = 1;
int v = temp->dest;
temp = temp->next;
int main() {
addEdge(graph, 0, 1, 10);
addEdge(graph, 0, 3, 30);
addEdge(graph, 0, 4, 100);
addEdge(graph, 1, 2, 50);
addEdge(graph, 2, 3, 20);
addEdge(graph, 2, 4, 10);
addEdge(graph, 3, 4, 60);
dijkstraList(graph, 0);
return 0;
OUTPUT:-
0 0
1 10
2 60
3 30
4 70
Result:
For most real-world applications (where graphs are often sparse), the adjacency list representation
combined with a priority queue (min-heap) is the better choice for implementing Dijkstra's algorithm.
AIM:- Implement Job Sequencing with deadlines using Greedy strategy.
Description:-
The Job Sequencing problem with deadlines is a classic optimization problem where you are given a set
of jobs, each with a deadline and profit associated with it. The objective is to schedule jobs in such a way
that the maximum profit is obtained, assuming that only one job can be performed at a time and the job
must be completed before its deadline.
Program:-
#include <stdio.h>
#include <stdlib.h>
struct Job {
};
max = jobs[i].deadline;
}
return max;
// Function to implement Job Sequencing with deadlines using the Greedy strategy
int result[maxDeadline];
// Find a free slot for this job (starting from the last possible slot)
if (result[j] == -1) {
totalProfit += jobs[i].profit;
break;
}
}
if (result[i] != -1) {
int main() {
};
jobSequencing(jobs, n);
return 0;
OUTPUT:-
Result:
This is a simple and efficient solution for the job sequencing problem using the greedy approach,
ensuring that we maximize profit by selecting jobs with higher profit earlier.
AIM:- Write a program to solve 0/1 Knapsack problem Using Dynamic Programming.
Description:-
The 0/1 Knapsack problem is a classic dynamic programming problem where you're given a set of items,
each with a weight and value, and a knapsack with a weight capacity. The goal is to determine the
maximum total value of items that can be placed in the knapsack without exceeding its weight capacity.
Program:-
#include <stdio.h>
return (a > b) ? a : b;
// Create a 2D array to store the maximum value for each weight and item combination
if (i == 0 || w == 0)
else
}
// The final answer (maximum value) will be in dp[n][W]
return dp[n][W];
int main() {
return 0;
OUTPUT:
Result:-
The maximum value that can be obtained with a knapsack capacity of 50 is 220, by selecting the second
and third items.
AIM:- Implement N-Queens Problem Using Backtracking.
Description:-
The N-Queens problem is a classic backtracking problem where the goal is to place N queens
on an N×N chessboard such that no two queens threaten each other. This means that no two
queens should be in the same row, column, or diagonal.
Program:-
#include <stdio.h>
#include <stdbool.h>
printf("\n");
int i, j;
if (board[i][col])
return false;
if (board[i][j])
return false;
if (board[i][j])
return false;
return true;
if (row >= N)
return true;
board[row][col] = 1;
return true;
board[row][col] = 0;
return false;
bool solveNQueens() {
if (!solveNQueensUtil(board, 0)) {
return false;
printSolution(board);
return true;
int main() {
solveNQueens();
return 0;
OUTPUT:
0 0 1 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 1
Result:
This is an efficient way to solve the N-Queens problem using the backtracking approach.
AIM:- Use Backtracking strategy to solve 0/1 Knapsack problem
Description:-
The 0/1 Knapsack problem can also be solved using the backtracking approach, although it is less
efficient compared to dynamic programming but can help in understanding the recursive exploration of
choices.
Program:-
#include <stdio.h>
int maxProfit = 0;
return (a > b) ? a : b;
// Parameters:
// n: Number of items
void knapsackBacktrack(int W, int wt[], int val[], int n, int currWeight, int currProfit, int index) {
if (currWeight > W) {
return;
}
maxProfit = currProfit;
if (index == n) {
return;
int main() {
OUTPUT:
Result:
The backtracking approach generates all possible subsets of items to find the optimal solution.
AIM:- Implement Travelling Sales Person problem using Branch and Bound approach.
Description:-
The Travelling Salesperson Problem (TSP) is a well-known NP-hard problem, where the
objective is to find the shortest possible route that visits every city exactly once and returns to the
starting city.
The Branch and Bound approach is a commonly used strategy to solve the TSP. It works by
systematically considering different subsets of routes (branches) and using bounds to eliminate
routes that cannot yield a better solution than the current best-known solution.
Program:-
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
int cost = 0;
return cost;
return minCost;
void branchAndBoundTSP(int adjMatrix[N][N], int currPath[], bool visited[], int level, int currCost, int
*minCost, int bestPath[]) {
// Base case: if we reached the last level (i.e., visited all cities)
if (level == N) {
// If the current cost is less than the best-known cost, update the solution
*minCost = currCost;
bestPath[i] = currPath[i];
return;
if (!visited[i]) {
visited[i] = true;
currPath[level] = i;
// Calculate the cost of adding this node to the path
// Calculate the lower bound to decide if we should continue exploring this path
// Proceed only if the current cost is promising (i.e., less than the best-known cost)
visited[i] = false;
int main() {
int adjMatrix[N][N] = {
{ 0, 10, 15, 20 },
{ 10, 0, 35, 25 },
{ 15, 35, 0, 30 },
};
// Array to store the current path and the best path found
visited[0] = true;
currPath[0] = 0;
// Call the branch and bound function to find the minimum cost path
return 0;
Output:
Minimum cost: 80
Best path: 0 1 3 2 0
Result:-
The minimum travel cost is 80, and the best route to achieve this cost is to visit cities in the order 0 -> 1 -
> 3 -> 2 -> 0.