Ads Lab Manual
Ads Lab Manual
return node;
}
struct Node *minValueNode(struct Node *node)
{
struct Node *current = node;
while (current->left != NULL)
current = current->left;
return current;
}
// Delete a nodes
struct Node *deleteNode(struct Node *root, int key)
{
// Find the node and delete it
if (root == NULL)
return root;
if (key < root->key)
root->left = deleteNode(root->left, key);
else if (key > root->key)
root->right = deleteNode(root->right, key);
else {
if ((root->left == NULL) || (root->right == NULL)) {
struct Node *temp = root->left ? root->left : root->right;
if (temp == NULL)
{
temp = root;
root = NULL;
} else
*root = *temp;
free(temp);
}
else
{
struct Node *temp = minValueNode(root->right);
root->key = temp->key;
root->right = deleteNode(root->right, temp->key);
}
}
if (root == NULL)
return root;
// Update the balance factor of each node and
// balance the tree
root->height = 1 + max(height(root->left),
height(root->right));
int balance = getBalance(root);
if (balance > 1 && getBalance(root->left) >= 0)
return rightRotate(root);
if (balance > 1 && getBalance(root->left) < 0) {
root->left = leftRotate(root->left);
return rightRotate(root);
}
if (balance < -1 && getBalance(root->right) <= 0)
return leftRotate(root);
if (balance < -1 && getBalance(root->right) > 0) {
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}
// Print the tree
void printPreOrder(struct Node *root)
{
if (root != NULL) {
printf("%d ", root->key);
printPreOrder(root->left);
printPreOrder(root->right);
}
}
int main() {
struct Node *root = NULL;
root = insertNode(root, 2);
root = insertNode(root, 1);
root = insertNode(root, 7);
root = insertNode(root, 4);
root = insertNode(root, 5);
root = insertNode(root, 3);
root = insertNode(root, 8);
printPreOrder(root);
root = deleteNode(root, 3);
printf("\nAfter deletion: ");
printPreOrder(root);
return 0;
}
b. Develop a solution to the given problem using AVL Trees.
21,26,30,9,4,14,28,18,15,10,2,3,7
AVL Tree
AVL Trees are Self-Balanced Binary Search Trees.
In AVL trees, the balancing factor of each node is either 0 or 1 or -1.
Balance Factor of AVL Tree calculated as = Height of Left Sub-tree - Height of Right Sub-tree
Construction of AVL Trees -
Insertion Operation is performed to construct the AVL Tree.
Inserting the element in the AVL tree is same as the insertion performed in BST.
After insertion, check the balance factor of each node of the resulting tree.
o After the insertion, the balance factor of each node is either 0 or 1 or -1, then the tree
is considered to be balanced, concludes the operation, and inserts the next element if
any.
o After the insertion, the balance factor of at least one node is not 0 or 1 or -1, then the
tree is considered to be imbalanced, perform the suitable rotation to balance the
tree, and after the tree is balanced, insert the next element if any.
Rotations used to Balance the AVL Tree -
After inserting an element in the AVL tree,
If a tree becomes imbalanced, then there exists one particular node in the tree by balancing
which the entire tree becomes balanced automatically.
To rebalance the tree, balance that particular node.
To find that particular node:
Traverse the path from the newly inserted node to the root node.
Check the balance factor of each node that is encountered while traversing the path.
The first encountered imbalanced node will be the node that needs to be balanced.
To balance that node:
Count three nodes in the direction of the leaf node.
Then, use the concept of AVL Tree Rotations to rebalance the tree.
o LL Rotation - In LL rotation, every node moves one position to left from the current
position.
o RR Rotation - In RR rotation, every node moves one position to right from the current
position.
o LR Rotation - In LR rotation, at first, every node moves one position to the left and then
one position to right from the current position.
o RL Rotation - In RL rotation, at first every node moves one position to right and then
one position to left from the current position.
Step-by-Step Construction of the AVL Tree for the given Sequence 21, 26, 30, 9, 4, 14, 28, 18,15,10,
2, 3, 7
Exercise – 2
a. Implement B- Trees and its operations.
// Searching a key on a B-tree in C
#include <stdio.h>
#include <stdlib.h>
#define MAX 3
#define MIN 2
struct BTreeNode {
int val[MAX + 1], count;
struct BTreeNode *link[MAX + 1];
};
struct BTreeNode *root;
// Create a node
struct BTreeNode *createNode(int val, struct BTreeNode *child) {
struct BTreeNode *newNode;
newNode = (struct BTreeNode *)malloc(sizeof(struct BTreeNode));
newNode->val[1] = val;
newNode->count = 1;
newNode->link[0] = root;
newNode->link[1] = child;
return newNode;
}
// Insert node
void insertNode(int val, int pos, struct BTreeNode *node,
struct BTreeNode *child) {
int j = node->count;
while (j > pos) {
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,
struct BTreeNode *child, struct BTreeNode **newNode) {
int median, j;
if (pos > MIN)
median = MIN + 1;
else
median = MIN;
*newNode = (struct BTreeNode *)malloc(sizeof(struct BTreeNode));
j = median + 1;
while (j <= MAX) {
(*newNode)->val[j - median] = node->val[j];
(*newNode)->link[j - median] = node->link[j];
j++;
}
node->count = median;
(*newNode)->count = MAX - median;
if (pos <= MIN) {
insertNode(val, pos, node, child);
} else {
insertNode(val, pos - median, *newNode, child);
}
*pval = node->val[node->count];
(*newNode)->link[0] = node->link[node->count];
node->count--;
}
// Set the value
int setValue(int val, int *pval,
struct BTreeNode *node, struct BTreeNode **child) {
int pos;
if (!node) {
*pval = val;
*child = NULL;
return 1;
}
if (val < node->val[1]) {
pos = 0;
} else {
for (pos = node->count;
(val < node->val[pos] && pos > 1); pos--)
;
if (val == node->val[pos]) {
printf("Duplicates are not permitted\n");
return 0;
}
}
if (setValue(val, pval, node->link[pos], child)) {
if (node->count < MAX) {
insertNode(*pval, pos, node, *child);
} else {
splitNode(*pval, pval, pos, node, *child, child);
return 1;
}
}
return 0;
}
// Insert the value
void insert(int val) {
int flag, i;
struct BTreeNode *child;
int main() {
int val, ch;
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);
}
b.
Exercise – 3
Program for max and min heap
#include <stdio.h>
#include <stdlib.h>
// Structure for Heap
typedef struct {
int *arr;
int size;
int capacity;
int isMaxHeap; // 1 for Max Heap, 0 for Min Heap
} Heap;
// Free memory
void freeHeap(Heap *heap) {
free(heap->arr);
free(heap);
}
// Main function
int main() {
int capacity, choice, value;
printf("Enter the capacity of the heap: ");
scanf("%d", &capacity);
printf("Choose Heap Type (1 for Max Heap, 0 for Min Heap): ");
int type;
scanf("%d", &type);
Heap *heap = createHeap(capacity, type);
while (1) {
printf("\n1. Insert\n2. Delete Root\n3. Display\n4. Exit\nEnter choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("Enter value to insert: ");
scanf("%d", &value);
insert(heap, value);
break;
case 2:
deleteRoot(heap);
break;
case 3:
displayHeap(heap);
break;
case 4:
freeHeap(heap);
exit(0);
default:
printf("Invalid choice!\n");
}
}
return 0;
}
Exercise -4
a. Implement Graph and its operations
#include <stdio.h>
#include <stdlib.h>
// Define a structure for the adjacency list node
typedef struct Node {
int vertex;
struct Node* next;
} Node;
// Define a structure for the graph
typedef struct Graph {
int numVertices;
Node** adjLists;
int* visited;
} Graph;
// Function to create a new node
Node* createNode(int vertex) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->vertex = vertex;
newNode->next = NULL;
return newNode;
}
// Function to create a graph
Graph* createGraph(int vertices) {
Graph* graph = (Graph*)malloc(sizeof(Graph));
graph->numVertices = vertices;
graph->adjLists = (Node**)malloc(vertices * sizeof(Node*));
graph->visited = (int*)malloc(vertices * sizeof(int));
for (int i = 0; i < vertices; i++) {
graph->adjLists[i] = NULL;
graph->visited[i] = 0;
}
return graph;
}
// Function to add an edge to the graph
void addEdge(Graph* graph, int src, int dest) {
// Add edge from src to dest
Node* newNode = createNode(dest);
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
Output:
Enter the number of vertices: 5
Enter the number of edges: 6
Enter the edges (source and destination):
Edge 1: 0 1
Edge 2: 0 4
Edge 3: 1 2
Edge 4: 1 3
Edge 5: 1 4
Edge 6: 3 4
Menu:
1. Display Graph
2. Depth-First Search (DFS)
3. Breadth-First Search (BFS)
4. Exit
Enter your choice: 1
Menu:
1. Display Graph
2. Depth-First Search (DFS)
3. Breadth-First Search (BFS)
4. Exit
Enter your choice: 2
Menu:
1. Display Graph
2. Depth-First Search (DFS)
3. Breadth-First Search (BFS)
4. Exit
Enter your choice: 3
Menu:
1. Display Graph
2. Depth-First Search (DFS)
3. Breadth-First Search (BFS)
4. Exit
Enter your choice: 4
Exiting program.
Exercise -5
Develop and implement an algorithm using divide and conquer strategy for a given set of problem
#include<stdio.h>
#include<stdio.h>
int max, min;
int a[100];
void maxmin(int i, int j)
{
int max1, min1, mid;
if(i==j)
{
max = min = a[i];
}
else
{
if(i == j-1)
{
if(a[i] <a[j])
{
max = a[j];
min = a[i];
}
else
{
max = a[i];
min = a[j];
}
}
else
{
mid = (i+j)/2;
maxmin(i, mid);
max1 = max; min1 = min;
maxmin(mid+1, j);
if(max <max1)
max = max1;
if(min > min1)
min = min1;
}
}
}
int main ()
{
int i, num;
printf ("\nEnter the total number of numbers : ");
scanf ("%d",&num);
printf ("Enter the numbers : \n");
for (i=1;i<=num;i++)
scanf ("%d",&a[i]);
max = a[0];
min = a[0];
maxmin(1, num);
printf ("Minimum element in an array : %d\n", min);
printf ("Maximum element in an array : %d\n", max);
return 0;
}
Output:
Enter the total number of numbers : 11
Enter the numbers :
5
1
9
45
19
15
17
100
0
56
13
Minimum element in an array : 0
Maximum element in an array : 100
Exercise:6
Make use of greedy method to implement a solution for a given problem
#include <stdio.h>
#define MAX 100
typedef struct Job {
char id[5];
int deadline;
int profit;
} Job;
void jobSequencingWithDeadline(Job jobs[], int n);
int minValue(int x, int y) {
if(x < y) return x;
return y;
}
int main(void) {
//variables
int i, j;
//jobs with deadline and profit
Job jobs[5] = {
{"j1", 2, 60},
{"j2", 1, 100},
{"j3", 3, 20},
{"j4", 2, 40},
{"j5", 1, 20},
};
//temp
Job temp;
//number of jobs
int n = 5;
//sort the jobs profit wise in descending order
for(i = 1; i < n; i++) {
for(j = 0; j < n - i; j++) {
if(jobs[j+1].profit > jobs[j].profit) {
temp = jobs[j+1];
jobs[j+1] = jobs[j];
jobs[j] = temp;
}
}
}
printf("%10s %10s %10s\n", "Job", "Deadline", "Profit");
for(i = 0; i < n; i++) {
printf("%10s %10i %10i\n", jobs[i].id, jobs[i].deadline, jobs[i].profit);
}
jobSequencingWithDeadline(jobs, n);
return 0;
}
void jobSequencingWithDeadline(Job jobs[], int n) {
//variables
int i, j, k, maxprofit;
//free time slots
int timeslot[MAX];
//filled time slots
int filledTimeSlot = 0;
//find max deadline value
int dmax = 0;
for(i = 0; i < n; i++) {
if(jobs[i].deadline > dmax) {
dmax = jobs[i].deadline;
}
}
//free time slots initially set to -1 [-1 denotes EMPTY]
for(i = 1; i <= dmax; i++) {
timeslot[i] = -1;
}
printf("dmax: %d\n", dmax);
for(i = 1; i <= n; i++) {
k = minValue(dmax, jobs[i - 1].deadline);
while(k >= 1) {
if(timeslot[k] == -1) {
timeslot[k] = i-1;
filledTimeSlot++;
break;
}
k--;
}
//if all time slots are filled then stop
if(filledTimeSlot == dmax) {
break;
}
}
//required jobs
printf("\nRequired Jobs: ");
for(i = 1; i <= dmax; i++) {
printf("%s", jobs[timeslot[i]].id);
if(i < dmax) {
printf(" --> ");
}
}
//required profit
maxprofit = 0;
for(i = 1; i <= dmax; i++) {
maxprofit += jobs[timeslot[i]].profit;
}
printf("\nMax Profit: %d\n", maxprofit);
}
Output:
Job Deadline Profit
j2 1 100
j1 2 60
j4 2 40
j3 3 20
j5 1 20
dmax: 3
b.)
#include<stdio.h>
int main()
{
float weight[50],profit[50],ratio[50],Totalvalue,temp,capacity,amount;
int n,i,j;
printf("Enter the number of items :");
scanf("%d",&n);
for (i = 0; i < n; i++)
{
printf("Enter Weight and Profit for item[%d] :\n",i);
scanf("%f %f", &weight[i], &profit[i]);
}
printf("Enter the capacity of knapsack :\n");
scanf("%f",&capacity);
for(i=0;i<n;i++)
ratio[i]=profit[i]/weight[i];
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
if (ratio[i] < ratio[j])
{
temp = ratio[j];
ratio[j] = ratio[i];
ratio[i] = temp;
temp = weight[j];
weight[j] = weight[i];
weight[i] = temp;
temp = profit[j];
profit[j] = profit[i];
profit[i] = temp;
}
int main() {
int n, W;
return 0;
}
Output:
Enter number of items: 3
Enter values of items: 1
2
5
Enter weights of items: 2
3
4
Enter Knapsack capacity: 6
Maximum value in Knapsack = 6
if (!solveNQueensUtil(board, 0, N)) {
printf("No solution exists for N = %d\n", N);
}
free(board);
}
int main() {
int N;
printf("Enter the number of queens (N): ");
scanf("%d", &N);
if (N <= 0) {
printf("Invalid input. N should be greater than 0.\n");
return 1;
}
solveNQueens(N);
return 0;
}
Output:
Enter the number of queens (N): 4
_ Q _ _
_ _ _ Q
Q _ _ _
_ _ Q _
_ _ Q _
Q _ _ _
_ _ _ Q
_ Q _ _
Output: 2
Enter the number of queens (N): 3
No solution exists for N = 3
Source code:
#include <stdio.h>
// Function to find the maximum value using Dynamic Programming
int knapsack(int W, int wt[], int val[], int n) {
int dp[n + 1][W + 1];
// Build the DP table
for (int i = 0; i <= n; i++) {
for (int w = 0; w <= W; w++) {
if (i == 0 || w == 0)
dp[i][w] = 0;
else if (wt[i - 1] <= w)
dp[i][w] = (val[i - 1] + dp[i - 1][w - wt[i - 1]] > dp[i - 1][w]) ?
val[i - 1] + dp[i - 1][w - wt[i - 1]] : dp[i - 1][w];
else
dp[i][w] = dp[i - 1][w];
}
}
return dp[n][W];
}
int main() {
int n, W;
printf("Enter number of items: ");
scanf("%d", &n);
int val[n], wt[n];
printf("Enter weight and value of each item (weight value):\n");
for (int i = 0; i < n; i++) {
scanf("%d %d", &wt[i], &val[i]);
}
printf("Enter maximum weight capacity: ");
scanf("%d", &W);
int maxProfit = knapsack(W, wt, val, n);
printf("Maximum value in Knapsack: %d\n", maxProfit);
return 0;
}
Output:
Enter number of items: 5
Enter weight and value of each item (weight value):
4
5
3
4
6
7
Enter maximum weight capacity: 15
Maximum value in Knapsack: 16
This C program uses a Dynamic Programming approach to solve the 0/1 Knapsack Problem. It
efficiently calculates the maximum possible value within the weight limit.
For Case Study 2, we can follow a structured approach to develop and implement an optimal
solution using a suitable design technique. Here's how you can approach it:
Step 1: Problem Understanding
Carefully read the given problem statement.
Identify the key elements: inputs, outputs, constraints, and goals.
Determine whether it's an optimization problem (e.g., finding the shortest path, maximizing
profit) or a decision problem (e.g., checking feasibility).
Step 2: Problem Formulation
Define the problem with clear variables, constraints, and objectives.
Example:
o Input: Set of data values, constraints, and objective function.
o Output: Optimal or feasible solution based on the constraints.
Step 3: Choose a Suitable Design Technique
Select the most appropriate design technique based on the problem nature:
1. Dynamic Programming (DP) - Suitable for problems with overlapping subproblems and
optimal substructure.
2. Greedy Algorithm - Ideal when making a local choice at each step leads to the optimal
solution.
3. Divide and Conquer - Best for breaking down large problems into smaller subproblems (e.g.,
Merge Sort, Quick Sort).
4. Backtracking - Effective for constraint satisfaction problems (e.g., N-Queens, Sudoku).
5. Branch and Bound - Used for optimization problems with large solution spaces (e.g.,
Knapsack, TSP).
6. Graph Algorithms - Applicable for network-related problems (e.g., shortest path, MST).
Example Problem for Case Study 2
Problem:
Given a graph represented as a weighted adjacency matrix, find the shortest path from a source node
to all other nodes using an optimal design technique.
Optimal Technique: Use Dijkstra’s Algorithm for shortest path finding in a weighted graph.
Reason: Efficient for graphs with non-negative weights.
Step 4: Implement the Solution
Here is a C implementation of Dijkstra’s Algorithm using a priority queue for optimization.
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#define MAX 100
int minDistance(int dist[], bool sptSet[], int V) {
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++) {
if (!sptSet[v] && dist[v] <= min) {
min = dist[v];
min_index = v;
}
}
return min_index;
}
void printSolution(int dist[], int V) {
printf("Vertex \t Distance from Source\n");
for (int i = 0; i < V; i++) {
printf("%d \t %d\n", i, dist[i]);
}
}
void dijkstra(int graph[MAX][MAX], int src, int V) {
int dist[V];
bool sptSet[V];
for (int i = 0; i < V; i++) {
dist[i] = INT_MAX;
sptSet[i] = false;
}
dist[src] = 0;
for (int count = 0; count < V - 1; count++) {
int u = minDistance(dist, sptSet, V);
sptSet[u] = true;
for (int v = 0; v < V; v++) {
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
}
}
}
printSolution(dist, V);
}
int main() {
int V;
printf("Enter number of vertices: ");
scanf("%d", &V);
int graph[MAX][MAX];
printf("Enter the adjacency matrix (use 0 for no edge):\n");
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
scanf("%d", &graph[i][j]);
}
}
int src;
printf("Enter source vertex: ");
scanf("%d", &src);