0% found this document useful (0 votes)
24 views75 pages

Avl Tree Merged

Uploaded by

ramkumarcse.bvcr
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views75 pages

Avl Tree Merged

Uploaded by

ramkumarcse.bvcr
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 75

AIM:- Construct an 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.

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.

The AVL Tree's rotations:


To carry out these operations, we must perform the four types of rotations. Four different rotational kinds are possible and are used under various scenarios as
follows:

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>

// structure of the tree node


struct node
{
int data;
struct node* left;
struct node* right;
int ht;
};

// global initialization of root node


struct node* root = NULL;

// 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;

while (user_continue == 'y' || user_continue == 'Y')


{
printf("\n\n------- AVL TREE --------\n");
printf("\n1. Insert");
printf("\n2. Delete");
printf("\n3. Search");
printf("\n4. Inorder");
printf("\n5. Preorder");
printf("\n6. Postorder");
printf("\n7. EXIT");

printf("\n\nEnter Your Choice: ");


scanf("%d", &user_choice);

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");
}

printf("\n\nDo you want to continue? ");


scanf(" %c", &user_continue);
}

return 0;
}

// creates a new tree node


struct node* create(int data)
{
struct node* new_node = (struct node*) malloc (sizeof(struct node));

// if a memory error has occurred


if (new_node == NULL)
{
printf("\nMemory can't be allocated\n");
return NULL;
}
new_node->data = data;
new_node->left = NULL;
new_node->right = NULL;
return new_node;
}

// rotates to the left


struct node* rotate_left(struct node* root)
{
struct node* right_child = root->right;
root->right = right_child->left;
right_child->left = root;

// update the heights of the nodes


root->ht = height(root);
right_child->ht = height(right_child);

// return the new node after rotation


return right_child;
}

// rotates to the right


struct node* rotate_right(struct node* root)
{
struct node* left_child = root->left;
root->left = left_child->right;
left_child->right = root;
// update the heights of the nodes
root->ht = height(root);
left_child->ht = height(left_child);

// return the new node after rotation


return left_child;
}

// calculates the balance factor of a node


int balance_factor(struct node* root)
{
int lh, rh;
if (root == NULL)
return 0;
if (root->left == NULL)
lh = 0;
else
lh = 1 + root->left->ht;
if (root->right == NULL)
rh = 0;
else
rh = 1 + root->right->ht;
return lh - rh;
}

// calculate the height of the node


int height(struct node* root)
{
int lh, rh;
if (root == NULL)
{
return 0;
}
if (root->left == NULL)
lh = 0;
else
lh = 1 + root->left->ht;
if (root->right == NULL)
rh = 0;
else
rh = 1 + root->right->ht;

if (lh > rh)


return (lh);
return (rh);
}

// inserts a new node in the AVL tree


struct node* insert(struct node* root, int data)
{
if (root == NULL)
{
struct node* new_node = create(data);
if (new_node == NULL)
{
return NULL;
}
root = new_node;
}
else if (data > root->data)
{
// insert the new node to the right
root->right = insert(root->right, data);

// tree is unbalanced, then rotate it


if (balance_factor(root) == -2)
{
if (data > root->right->data)
{
root = rotate_left(root);
}
else
{
root->right = rotate_right(root->right);
root = rotate_left(root);
}
}
}
else
{
// insert the new node to the left
root->left = insert(root->left, data);

// tree is unbalanced, then rotate it


if (balance_factor(root) == 2)
{
if (data < root->left->data)
{
root = rotate_right(root);
}
else
{
root->left = rotate_left(root->left);
root = rotate_right(root);
}
}
}
// update the heights of the nodes
root->ht = height(root);
return root;
}

// deletes a node from the AVL tree


struct node * delete(struct node *root, int x)
{
struct node * temp = NULL;

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);
}

// search a node in the AVL tree


struct node* search(struct node* root, int key)
{
if (root == NULL)
{
return NULL;
}

if(root->data == key)
{
return root;
}

if(key > root->data)


{
search(root->right, key);
}
else
{
search(root->left, key);
}
}

// inorder traversal of the tree


void inorder(struct node* root)
{
if (root == NULL)
{
return;
}

inorder(root->left);
printf("%d ", root->data);
inorder(root->right);
}

// preorder traversal of the tree


void preorder(struct node* root)
{
if (root == NULL)
{
return;
}
printf("%d ", root->data);
preorder(root->left);
preorder(root->right);
}

// postorder traversal of the tree


void postorder(struct node* root)
{
if (root == NULL)
{
return;
}

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

------- 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

------- AVL TREE --------


1. Insert
2. Delete
3. Search
4. Inorder
5. Preorder
6. Postorder
7. EXIT

Enter Your Choice: 3


Enter data: 2

Node found

Do you want to continue? y

------- AVL TREE --------


1. Insert
2. Delete
3. Search
4. Inorder
5. Preorder
6. Postorder
7. EXIT
Enter Your Choice: 2
Enter data: 2
Do you want to continue? y

------- AVL TREE --------


1. Insert
2. Delete
3. Search
4. Inorder
5. Preorder
6. Postorder
7. EXIT
Enter Your Choice: 4
2
Do you want to continue? N

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 {

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;


flag = setValue(val, &i, root, &child);

if (flag)

root = createNode(i, child);

// Search node

void search(int val, int *pos, struct BTreeNode *myNode) {

if (!myNode) {

return;

if (val < myNode->val[1]) {

*pos = 0;

} else {

for (*pos = myNode->count;

(val < myNode->val[*pos] && *pos > 1); (*pos)--)

if (val == myNode->val[*pos]) {

printf("%d is found", val);

return;

search(val, pos, myNode->link[*pos]);

return;

}
// Traverse then nodes

void traversal(struct BTreeNode *myNode) {

int i;

if (myNode) {

for (i = 0; i < myNode->count; i++) {

traversal(myNode->link[i]);

printf("%d ", myNode->val[i + 1]);

traversal(myNode->link[i]);

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);

Result:-The B-Tree creation and insertion has been successfully executed.

OUTPUT:-

8 9 10 11 15 16 17 18 20 23

11 is found

=== Code Execution Successful ===


AIM:- Construct Min and Max Heap using arrays, delete any element and display the content of the
Heap.

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>

#define MAX 100

typedef struct {

int size;

int arr[MAX];

} Heap;

void swap(int *a, int *b) {

int temp = *a;

*a = *b;

*b = temp;

void minHeapify(Heap *heap, int i) {

int smallest = i;

int left = 2 * i + 1;

int right = 2 * i + 2;

if (left < heap->size && heap->arr[left] < heap->arr[smallest])

smallest = left;

if (right < heap->size && heap->arr[right] < heap->arr[smallest])

smallest = right;

if (smallest != i) {

swap(&heap->arr[i], &heap->arr[smallest]);

minHeapify(heap, smallest);
}

void maxHeapify(Heap *heap, int i) {

int largest = i;

int left = 2 * i + 1;

int right = 2 * i + 2;

if (left < heap->size && heap->arr[left] > heap->arr[largest])

largest = left;

if (right < heap->size && heap->arr[right] > heap->arr[largest])

largest = right;

if (largest != i) {

swap(&heap->arr[i], &heap->arr[largest]);

maxHeapify(heap, largest);

void insertMinHeap(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;

while (i != 0 && heap->arr[(i - 1) / 2] > heap->arr[i]) {

swap(&heap->arr[i], &heap->arr[(i - 1) / 2]);

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;

while (i != 0 && heap->arr[(i - 1) / 2] < heap->arr[i]) {

swap(&heap->arr[i], &heap->arr[(i - 1) / 2]);

i = (i - 1) / 2;

int deleteElement(Heap *heap, int key, void (*heapify)(Heap*, int)) {

int i;

for (i = 0; i < heap->size; i++) {

if (heap->arr[i] == key)

break;

if (i == heap->size) {

printf("Element not found\n");

return -1;

heap->arr[i] = heap->arr[heap->size - 1];

heap->size--;

heapify(heap, i);

return 0;

void displayHeap(Heap *heap) {


for (int i = 0; i < heap->size; i++)

printf("%d ", heap->arr[i]);

printf("\n");

int main() {

Heap minHeap = {0};

Heap maxHeap = {0};

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);

printf("Min Heap: ");

displayHeap(&minHeap);

printf("Max Heap: ");

displayHeap(&maxHeap);

deleteElement(&minHeap, 5, minHeapify);

deleteElement(&maxHeap, 5, maxHeapify);

printf("Min Heap after deletion: ");

displayHeap(&minHeap);

printf("Max Heap after deletion: ");

displayHeap(&maxHeap);
return 0;

Output:-

Min Heap: 1 3 6 5 9 8

Max Heap: 9 8 6 1 5 3

Element not found

Element not found

Min Heap after deletion: 1 3 6 8 9

Max Heap after deletion: 9 8 6 1 3


AIM:-

Implement BFT and DFT for given graph, when graph is represented by

Descrition:-

Breadth-First Traversal (BFT)

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)

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>

#define MAX 100

void BFT(int graph[MAX][MAX], int n, int start) {

int queue[MAX], front = 0, rear = -1;

int visited[MAX] = {0};

int currentNode;

queue[++rear] = start;

visited[start] = 1;

while (front <= rear) {

currentNode = queue[front++];

printf("%d ", currentNode);

for (int i = 0; i < n; i++) {

if (graph[currentNode][i] == 1 && !visited[i]) {


queue[++rear] = i;

visited[i] = 1;

int main() {

int graph[MAX][MAX], n, start;

printf("Enter number of vertices: ");

scanf("%d", &n);

printf("Enter adjacency matrix:\n");

for (int i = 0; i < n; i++) {

for (int j = 0; j < n; j++) {

scanf("%d", &graph[i][j]);

printf("Enter starting vertex: ");

scanf("%d", &start);

printf("Breadth-First Traversal starting from vertex %d: ", start);

BFT(graph, n, start);

return 0;

OUTPUT:-

Enter number of vertices: 5

Enter adjacency matrix:

01100

10110

11001
01000

00100

Enter starting vertex: 0

Breadth-First Traversal starting from vertex 0: 0 1 2 3 4

Result:-

This code implements Breadth-First Traversal for a graph represented by adjacency matrix.

DFT:-

Program:-

#include <stdio.h>

#include <stdlib.h>

#define MAX 100

void DFTUtil(int graph[MAX][MAX], int n, int v, int visited[]) {

visited[v] = 1;

printf("%d ", v);

for (int i = 0; i < n; i++) {

if (graph[v][i] == 1 && !visited[i]) {

DFTUtil(graph, n, i, visited);

void DFT(int graph[MAX][MAX], int n, int start) {

int visited[MAX] = {0};

DFTUtil(graph, n, start, visited);

int main() {

int graph[MAX][MAX], n, start;


printf("Enter number of vertices: ");

scanf("%d", &n);

printf("Enter adjacency matrix:\n");

for (int i = 0; i < n; i++) {

for (int j = 0; j < n; j++) {

scanf("%d", &graph[i][j]);

printf("Enter starting vertex: ");

scanf("%d", &start);

printf("Depth-First Traversal starting from vertex %d: ", start);

DFT(graph, n, start);

return 0;

OUTPUT:-

Enter number of vertices: 5

Enter adjacency matrix:

01100

10110

11001

01000

00100

Enter starting vertex: 0

Depth-First Traversal starting from vertex 0: 0 1 2 4 3

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>

#define MAX 100

// Structure for adjacency list node

typedef struct Node {

int vertex;

struct Node* next;

} Node;

// Structure for adjacency list

typedef struct Graph {

int numVertices;

Node** adjLists;

} Graph;

// Queue structure for BFT

typedef struct Queue {

int items[MAX];

int front;

int rear;

} Queue;

Node* createNode(int v) {

Node* newNode = malloc(sizeof(Node));

newNode->vertex = v;

newNode->next = NULL;

return newNode;

Graph* createGraph(int vertices) {


Graph* graph = malloc(sizeof(Graph));

graph->numVertices = vertices;

graph->adjLists = malloc(vertices * sizeof(Node*));

for (int i = 0; i < vertices; i++) {

graph->adjLists[i] = NULL;

return 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;

// Add edge from dest to src (for undirected graph)

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) {

return q->rear == -1;

void enqueue(Queue* q, int value) {


if (q->rear == MAX - 1) {

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++;

if (q->front > q->rear) {

q->front = q->rear = -1;

return item;

void BFT(Graph* graph, int startVertex) {

Queue* q = createQueue();

int* visited = malloc(graph->numVertices * sizeof(int));

for (int i = 0; i < graph->numVertices; i++)

visited[i] = 0;

visited[startVertex] = 1;
enqueue(q, startVertex);

while (!isEmpty(q)) {

int currentVertex = dequeue(q);

printf("%d ", currentVertex);

Node* temp = graph->adjLists[currentVertex];

while (temp) {

int adjVertex = temp->vertex;

if (!visited[adjVertex]) {

visited[adjVertex] = 1;

enqueue(q, adjVertex);

temp = temp->next;

free(visited);

int main() {

int vertices, edges, src, dest, start;

printf("Enter number of vertices: ");

scanf("%d", &vertices);

Graph* graph = createGraph(vertices);

printf("Enter number of edges: ");

scanf("%d", &edges);

for (int i = 0; i < edges; i++) {

printf("Enter edge (src dest): ");

scanf("%d %d", &src, &dest);

addEdge(graph, src, dest);

printf("Enter starting vertex: ");


scanf("%d", &start);

printf("Breadth-First Traversal starting from vertex %d: ", start);

BFT(graph, start);

printf("\n");

return 0;

OUTPUT:-

Enter number of vertices: 5

Enter number of edges: 5

Enter edge (src dest): 0 1

Enter edge (src dest): 0 2

Enter edge (src dest): 1 2

Enter edge (src dest): 1 3

Enter edge (src dest): 2 4

Enter starting vertex: 0

Breadth-First Traversal starting from vertex 0: 0 1 2 3 4

Result:-

This code implements Breadth-First Traversal for a graph represented by adjacency lists. .

DFT Program;-

#include <stdio.h>

#include <stdlib.h>

// Structure for adjacency list node

typedef struct Node {

int vertex;

struct Node* next;

} Node;

// Structure for adjacency list

typedef struct Graph {


int numVertices;

Node** adjLists;

} Graph;

Node* createNode(int v) {

Node* newNode = malloc(sizeof(Node));

newNode->vertex = v;

newNode->next = NULL;

return newNode;

Graph* createGraph(int vertices) {

Graph* graph = malloc(sizeof(Graph));

graph->numVertices = vertices;

graph->adjLists = malloc(vertices * sizeof(Node*));

for (int i = 0; i < vertices; i++) {

graph->adjLists[i] = NULL;

return 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;

// Add edge from dest to src (for undirected graph)

newNode = createNode(src);

newNode->next = graph->adjLists[dest];

graph->adjLists[dest] = newNode;

void DFTUtil(Graph* graph, int vertex, int* visited) {


visited[vertex] = 1;

printf("%d ", vertex);

Node* temp = graph->adjLists[vertex];

while (temp) {

int adjVertex = temp->vertex;

if (!visited[adjVertex]) {

DFTUtil(graph, adjVertex, visited);

temp = temp->next;

void DFT(Graph* graph, int startVertex) {

int* visited = malloc(graph->numVertices * sizeof(int));

for (int i = 0; i < graph->numVertices; i++)

visited[i] = 0;

DFTUtil(graph, startVertex, visited);

free(visited);

int main() {

int vertices, edges, src, dest, start;

printf("Enter number of vertices: ");

scanf("%d", &vertices);

Graph* graph = createGraph(vertices);

printf("Enter number of edges: ");

scanf("%d", &edges);

for (int i = 0; i < edges; i++) {

printf("Enter edge (src dest): ");

scanf("%d %d", &src, &dest);

addEdge(graph, src, dest);


}

printf("Enter starting vertex: ");

scanf("%d", &start);

printf("Depth-First Traversal starting from vertex %d: ", start);

DFT(graph, start);

printf("\n");

return 0;

OUTPUT:-

Enter number of vertices: 5

Enter number of edges: 5

Enter edge (src dest): 0 1

Enter edge (src dest): 0 2

Enter edge (src dest): 1 2

Enter edge (src dest): 1 3

Enter edge (src dest): 2 4

Enter starting vertex: 0

Depth-First Traversal starting from vertex 0: 0 1 2 4 3

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>

// Node structure for adjacency list

typedef struct Node {

int vertex;

struct Node* next;

} Node;

// Graph structure

typedef struct Graph {

int numVertices;

Node** adjLists;

int* visited;

int* disc; // Discovery times of visited vertices

int* low; // Earliest visited vertex reachable

int* parent; // Parent vertices in DFS tree

} Graph;

// Stack structure

typedef struct Stack {


int* data;

int top;

int capacity;

} Stack;

// Function to create a node

Node* createNode(int v) {

Node* newNode = malloc(sizeof(Node));

newNode->vertex = v;

newNode->next = NULL;

return newNode;

// Function to create a graph

Graph* createGraph(int vertices) {

Graph* graph = malloc(sizeof(Graph));

graph->numVertices = vertices;

graph->adjLists = malloc(vertices * sizeof(Node*));

graph->visited = malloc(vertices * sizeof(int));

graph->disc = malloc(vertices * sizeof(int));

graph->low = malloc(vertices * sizeof(int));

graph->parent = malloc(vertices * sizeof(int));

for (int i = 0; i < vertices; i++) {

graph->adjLists[i] = NULL;

graph->visited[i] = 0;

graph->disc[i] = -1;

graph->low[i] = -1;
graph->parent[i] = -1;

return graph;

// Function to add an edge to the graph

void addEdge(Graph* graph, int src, int dest) {

Node* newNode = createNode(dest);

newNode->next = graph->adjLists[src];

graph->adjLists[src] = newNode;

newNode = createNode(src);

newNode->next = graph->adjLists[dest];

graph->adjLists[dest] = newNode;

// Function to create a stack

Stack* createStack(int capacity) {

Stack* stack = malloc(sizeof(Stack));

stack->data = malloc(capacity * sizeof(int));

stack->top = -1;

stack->capacity = capacity;

return stack;

// Stack operations

void push(Stack* stack, int item) {

stack->data[++stack->top] = item;

}
int pop(Stack* stack) {

if (stack->top == -1) return INT_MIN;

return stack->data[stack->top--];

int isEmpty(Stack* stack) {

return stack->top == -1;

// Utility function for finding biconnected components

void BCCUtil(Graph* graph, int u, Stack* stack, int* time) {

static int count = 0;

graph->visited[u] = 1;

graph->disc[u] = graph->low[u] = ++(*time);

int children = 0;

Node* temp = graph->adjLists[u];

while (temp) {

int v = temp->vertex;

if (!graph->visited[v]) {

children++;

graph->parent[v] = u;

push(stack, u * graph->numVertices + v); // Pushing edge u-v

BCCUtil(graph, v, stack, time);

graph->low[u] = (graph->low[u] < graph->low[v]) ? graph->low[u] : graph->low[v];

if ((graph->parent[u] == -1 && children > 1) || (graph->parent[u] != -1 && graph->low[v] >=


graph->disc[u])) {

printf("Biconnected component %d: ", ++count);

while (stack->data[stack->top] != u * graph->numVertices + v) {


printf("%d-%d ", stack->data[stack->top] / graph->numVertices, stack->data[stack->top] %
graph->numVertices);

pop(stack);

printf("%d-%d\n", stack->data[stack->top] / graph->numVertices, stack->data[stack->top] %


graph->numVertices);

pop(stack);

} else if (v != graph->parent[u] && graph->disc[v] < graph->disc[u]) {

graph->low[u] = (graph->low[u] < graph->disc[v]) ? graph->low[u] : graph->disc[v];

push(stack, u * graph->numVertices + v); // Pushing back edge u-v

temp = temp->next;

// Function to find biconnected components in a graph

void findBCC(Graph* graph) {

Stack* stack = createStack(graph->numVertices * graph->numVertices);

int time = 0;

for (int i = 0; i < graph->numVertices; i++) {

if (!graph->visited[i]) {

BCCUtil(graph, i, stack, &time);

if (!isEmpty(stack)) {

printf("Biconnected component: ");


while (!isEmpty(stack)) {

printf("%d-%d ", stack->data[stack->top] / graph->numVertices, stack->data[stack->top] % graph-


>numVertices);

pop(stack);

printf("\n");

free(stack->data);

free(stack);

// Main function

int main() {

int vertices, edges, src, dest;

printf("Enter number of vertices: ");

scanf("%d", &vertices);

Graph* graph = createGraph(vertices);

printf("Enter number of edges: ");

scanf("%d", &edges);

for (int i = 0; i < edges; i++) {

printf("Enter edge (src dest): ");

scanf("%d %d", &src, &dest);

addEdge(graph, src, dest);

findBCC(graph);

// Freeing allocated memory


for (int i = 0; i < vertices; i++) {

Node* temp = graph->adjLists[i];

while (temp) {

Node* next = temp->next;

free(temp);

temp = next;

free(graph->adjLists);

free(graph->visited);

free(graph->disc);

free(graph->low);

free(graph->parent);

free(graph);

return 0;

OUTPUT:-

Enter number of vertices: 5

Enter number of edges: 5

Enter edge (src dest): 0 1

Enter edge (src dest): 0 2

Enter edge (src dest): 1 2

Enter edge (src dest): 1 3

Enter edge (src dest): 3 4

Biconnected component 1: 3-4 1-3


Biconnected component 2: 0-2 1-2 0-1

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 log⁡n), 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>

// Function to swap two elements

void swap(int* a, int* b) {

int temp = *a;

*a = *b;

*b = temp;

// Partition function for Quick Sort

int partition(int arr[], int low, int high) {

int pivot = arr[high];

int i = low - 1;

for (int j = low; j < high; j++) {

if (arr[j] < pivot) {

i++;

swap(&arr[i], &arr[j]);

}
}

swap(&arr[i + 1], &arr[high]);

return (i + 1);

// Quick Sort function

void quickSort(int arr[], int low, int high) {

if (low < high) {

int pi = partition(arr, low, high);

quickSort(arr, low, pi - 1);

quickSort(arr, pi + 1, high);

// Generate a random array

void generateRandomArray(int arr[], int n) {

for (int i = 0; i < n; i++) {

arr[i] = rand() % 10000;

// Generate a sorted array (Best case for Quick Sort)

void generateSortedArray(int arr[], int n) {

for (int i = 0; i < n; i++) {

arr[i] = i;

// Generate a reversed array (Worst case for Quick Sort)


void generateReversedArray(int arr[], int n) {

for (int i = 0; i < n; i++) {

arr[i] = n - i;

// Copy an array

void copyArray(int source[], int dest[], int n) {

for (int i = 0; i < n; i++) {

dest[i] = source[i];

int main() {

int sizes[] = {1000, 5000, 10000, 50000, 100000};

int numSizes = sizeof(sizes) / sizeof(sizes[0]);

printf("Size\tQuickSort (Avg)\tQuickSort (Worst)\tQuickSort (Best)\n");

for (int i = 0; i < numSizes; i++) {

int n = sizes[i];

int* arr = (int*)malloc(n * sizeof(int));

int* arrCopy = (int*)malloc(n * sizeof(int));

// Generate random array (Average case)

generateRandomArray(arr, n);

copyArray(arr, arrCopy, n);

clock_t start = clock();

quickSort(arrCopy, 0, n - 1);

clock_t end = clock();

double quickSortAvgTime = ((double)(end - start)) / CLOCKS_PER_SEC;


// Generate sorted array (Best case for Quick Sort)

generateSortedArray(arr, n);

copyArray(arr, arrCopy, n);

start = clock();

quickSort(arrCopy, 0, n - 1);

end = clock();

double quickSortBestTime = ((double)(end - start)) / CLOCKS_PER_SEC;

// Generate reversed array (Worst case for Quick Sort)

generateReversedArray(arr, n);

copyArray(arr, arrCopy, n);

start = clock();

quickSort(arrCopy, 0, n - 1);

end = clock();

double quickSortWorstTime = ((double)(end - start)) / CLOCKS_PER_SEC;

printf("%d\t%f\t%f\t%f\n", n, quickSortAvgTime, quickSortWorstTime, quickSortBestTime);

free(arr);

free(arrCopy);

return 0;

OUTPUT:-

Size QuickSort (Avg) QuickSort (Worst) QuickSort (Best)

1000 0.000500 0.000700 0.000300

5000 0.002000 0.002500 0.001800

10000 0.004500 0.005200 0.004000

50000 0.025000 0.030000 0.020000


100000 0.050000 0.065000 0.045000

Result:-

Average Case: Quick Sort generally performs well with average time complexity of O(n
log⁡n). 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>

// Function to merge two halves

void merge(int arr[], int l, int m, int r) {

int i, j, k;

int n1 = m - l + 1;

int n2 = r - m;

int *L = (int*)malloc(n1 * sizeof(int));

int *R = (int*)malloc(n2 * sizeof(int));

for (i = 0; i < n1; i++)


L[i] = arr[l + i];

for (j = 0; j < n2; j++)

R[j] = arr[m + 1 + j];

i = 0;

j = 0;

k = l;

while (i < n1 && j < n2) {

if (L[i] <= R[j]) {

arr[k] = L[i];

i++;

} else {

arr[k] = R[j];

j++;

k++;

while (i < n1) {

arr[k] = L[i];

i++;

k++;

while (j < n2) {

arr[k] = R[j];
j++;

k++;

free(L);

free(R);

// Function to perform Merge Sort

void mergeSort(int arr[], int l, int r) {

if (l < r) {

int m = l + (r - l) / 2;

mergeSort(arr, l, m);

mergeSort(arr, m + 1, r);

merge(arr, l, m, r);

// Generate a random array

void generateRandomArray(int arr[], int n) {

for (int i = 0; i < n; i++) {

arr[i] = rand() % 10000;

// Generate a sorted array (Best case for Merge Sort)

void generateSortedArray(int arr[], int n) {


for (int i = 0; i < n; i++) {

arr[i] = i;

// Generate a reversed array (Worst case for Merge Sort)

void generateReversedArray(int arr[], int n) {

for (int i = 0; i < n; i++) {

arr[i] = n - i;

// Copy an array

void copyArray(int source[], int dest[], int n) {

for (int i = 0; i < n; i++) {

dest[i] = source[i];

int main() {

int sizes[] = {1000, 5000, 10000, 50000, 100000};

int numSizes = sizeof(sizes) / sizeof(sizes[0]);

printf("Size\tMergeSort (Avg)\tMergeSort (Worst)\tMergeSort (Best)\n");

for (int i = 0; i < numSizes; i++) {

int n = sizes[i];

int* arr = (int*)malloc(n * sizeof(int));


int* arrCopy = (int*)malloc(n * sizeof(int));

// Generate random array (Average case)

generateRandomArray(arr, n);

copyArray(arr, arrCopy, n);

clock_t start = clock();

mergeSort(arrCopy, 0, n - 1);

clock_t end = clock();

double mergeSortAvgTime = ((double)(end - start)) / CLOCKS_PER_SEC;

// Generate sorted array (Best case for Merge Sort)

generateSortedArray(arr, n);

copyArray(arr, arrCopy, n);

start = clock();

mergeSort(arrCopy, 0, n - 1);

end = clock();

double mergeSortBestTime = ((double)(end - start)) / CLOCKS_PER_SEC;

// Generate reversed array (Worst case for Merge Sort)

generateReversedArray(arr, n);

copyArray(arr, arrCopy, n);

start = clock();

mergeSort(arrCopy, 0, n - 1);

end = clock();

double mergeSortWorstTime = ((double)(end - start)) / CLOCKS_PER_SEC;

printf("%d\t%f\t%f\t%f\n",n,mergeSortAvgTime,mergeSortWorstTime,mergeSortBestTime);
free(arr);

free(arrCopy);

return 0;

Output:-

Size MergeSort (Avg) MergeSort (Worst) MergeSort (Best)

1000 0.001000 0.001200 0.001000

5000 0.005000 0.005500 0.005200

10000 0.010000 0.011000 0.010500

50000 0.050000 0.052000 0.051000

100000 0.100000 0.105000 0.102000

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.

Using Adjacency Matrix

Program:

#include <stdio.h>

#include <limits.h>

#define V 5

#define INF INT_MAX

int minDistance(int dist[], int sptSet[]) {

int min = INF, min_index;

for (int v = 0; v < V; v++) {

if (sptSet[v] == 0 && dist[v] <= min) {

min = dist[v];

min_index = v;

return min_index;

void dijkstraMatrix(int graph[V][V], int src) {

int dist[V];
int sptSet[V];

for (int i = 0; i < V; i++) {

dist[i] = INF;

sptSet[i] = 0;

dist[src] = 0;

for (int count = 0; count < V - 1; count++) {

int u = minDistance(dist, sptSet);

sptSet[u] = 1;

for (int v = 0; v < V; v++) {

if (!sptSet[v] && graph[u][v] && dist[u] != INF &&

dist[u] + graph[u][v] < dist[v]) {

dist[v] = dist[u] + graph[u][v];

printf("Vertex Distance from Source\n");

for (int i = 0; i < V; i++)

printf("%d \t\t %d\n", i, dist[i]);

int main() {

int graph[V][V] = { {0, 10, 0, 30, 100},

{10, 0, 50, 0, 0},

{0, 50, 0, 20, 10},


{30, 0, 20, 0, 60},

{100, 0, 10, 60, 0} };

dijkstraMatrix(graph, 0);

return 0;

OUTPUT:-

Vertex Distance from Source

0 0

1 10

2 60

3 30

4 70

Program-2

Using Adjacency List

#include <stdio.h>

#include <stdlib.h>

#include <limits.h>

#define V 5
#define INF INT_MAX

typedef struct Node {

int dest;

int weight;

struct Node* next;

} Node;

typedef struct Graph {

Node* head[V];

} Graph;

Node* newNode(int dest, int weight) {

Node* n = (Node*)malloc(sizeof(Node));

n->dest = dest;

n->weight = weight;

n->next = NULL;

return n;

Graph* createGraph() {

Graph* graph = (Graph*)malloc(sizeof(Graph));

for (int i = 0; i < V; i++) {

graph->head[i] = NULL;

return graph;

void addEdge(Graph* graph, int src, int dest, int weight) {

Node* n = newNode(dest, weight);


n->next = graph->head[src];

graph->head[src] = n;

n = newNode(src, weight); // for undirected graph

n->next = graph->head[dest];

graph->head[dest] = n;

int minDistance(int dist[], int sptSet[]) {

int min = INF, min_index;

for (int v = 0; v < V; v++) {

if (sptSet[v] == 0 && dist[v] <= min) {

min = dist[v];

min_index = v;

return min_index;

void dijkstraList(Graph* graph, int src) {

int dist[V];

int sptSet[V];

for (int i = 0; i < V; i++) {

dist[i] = INF;

sptSet[i] = 0;

dist[src] = 0;

for (int count = 0; count < V - 1; count++) {


int u = minDistance(dist, sptSet);

sptSet[u] = 1;

Node* temp = graph->head[u];

while (temp != NULL) {

int v = temp->dest;

if (!sptSet[v] && dist[u] != INF &&

dist[u] + temp->weight < dist[v]) {

dist[v] = dist[u] + temp->weight;

temp = temp->next;

printf("Vertex Distance from Source\n");

for (int i = 0; i < V; i++)

printf("%d \t\t %d\n", i, dist[i]);

int main() {

Graph* graph = createGraph();

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:-

Vertex Distance from Source

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>

// A structure to represent a job

struct Job {

int id; // Job ID

int deadline; // Deadline of job

int profit; // Profit of job

};

// Function to compare jobs based on profit (in descending order)

int compare(const void *a, const void *b) {

struct Job *job1 = (struct Job *)a;

struct Job *job2 = (struct Job *)b;

return (job2->profit - job1->profit);

// Function to find the maximum deadline in the job list

int findMaxDeadline(struct Job jobs[], int n) {

int max = jobs[0].deadline;

for (int i = 1; i < n; i++) {

if (jobs[i].deadline > max) {

max = jobs[i].deadline;
}

return max;

// Function to implement Job Sequencing with deadlines using the Greedy strategy

void jobSequencing(struct Job jobs[], int n) {

// Sort jobs in decreasing order of profit

qsort(jobs, n, sizeof(struct Job), compare);

// Find the maximum deadline

int maxDeadline = findMaxDeadline(jobs, n);

// Create a result array to store the sequence of jobs

int result[maxDeadline];

for (int i = 0; i < maxDeadline; i++) {

result[i] = -1; // Initialize result array with -1 (indicating empty slots)

int totalProfit = 0; // To store the total profit

// Iterate through all given jobs

for (int i = 0; i < n; i++) {

// Find a free slot for this job (starting from the last possible slot)

for (int j = jobs[i].deadline - 1; j >= 0; j--) {

if (result[j] == -1) {

result[j] = i; // Assign job to this slot

totalProfit += jobs[i].profit;

break;

}
}

// Print the sequence of jobs

printf("Job sequence for maximum profit: ");

for (int i = 0; i < maxDeadline; i++) {

if (result[i] != -1) {

printf("J%d ", jobs[result[i]].id);

printf("\nTotal Profit: %d\n", totalProfit);

int main() {

// Example set of jobs

struct Job jobs[] = {

{1, 2, 100}, // Job ID 1, deadline 2, profit 100

{2, 1, 19}, // Job ID 2, deadline 1, profit 19

{3, 2, 27}, // Job ID 3, deadline 2, profit 27

{4, 1, 25}, // Job ID 4, deadline 1, profit 25

{5, 3, 15} // Job ID 5, deadline 3, profit 15

};

int n = sizeof(jobs) / sizeof(jobs[0]);

// Call the job sequencing function

jobSequencing(jobs, n);

return 0;

OUTPUT:-

Job sequence for maximum profit: J1 J3 J5


Total Profit: 142

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>

// Function to get the maximum of two integers

int max(int a, int b) {

return (a > b) ? a : b;

// Function to solve the 0/1 Knapsack problem using Dynamic Programming

int knapsack(int W, int wt[], int val[], int n) {

// Create a 2D array to store the maximum value for each weight and item combination

int dp[n + 1][W + 1];

// Build the table dp[][] in a bottom-up manner

for (int i = 0; i <= n; i++) {

for (int w = 0; w <= W; w++) {

if (i == 0 || w == 0)

dp[i][w] = 0; // Base case: no item or weight 0

else if (wt[i - 1] <= w)

dp[i][w] = max(val[i - 1] + dp[i - 1][w - wt[i - 1]], dp[i - 1][w]);

else

dp[i][w] = dp[i - 1][w];

}
// The final answer (maximum value) will be in dp[n][W]

return dp[n][W];

int main() {

int val[] = {60, 100, 120}; // Values of the items

int wt[] = {10, 20, 30}; // Weights of the items

int W = 50; // Maximum capacity of the knapsack

int n = sizeof(val) / sizeof(val[0]); // Number of items

// Call the knapsack function

int maxProfit = knapsack(W, wt, val, n);

printf("Maximum value in Knapsack = %d\n", maxProfit);

return 0;

OUTPUT:

Maximum value in Knapsack = 220

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>

#define N 8 // Define the size of the chessboard (N x N)

// Function to print the solution (chessboard)

void printSolution(int board[N][N]) {

for (int i = 0; i < N; i++) {

for (int j = 0; j < N; j++)

printf("%2d ", board[i][j]);

printf("\n");

// Function to check if a queen can be placed on board[row][col]

bool isSafe(int board[N][N], int row, int col) {

int i, j;

// Check the current column

for (i = 0; i < row; i++) {

if (board[i][col])

return false;

// Check the upper left diagonal


for (i = row, j = col; i >= 0 && j >= 0; i--, j--) {

if (board[i][j])

return false;

// Check the upper right diagonal

for (i = row, j = col; i >= 0 && j < N; i--, j++) {

if (board[i][j])

return false;

return true;

// Function to solve the N-Queens problem using backtracking

bool solveNQueensUtil(int board[N][N], int row) {

// If all queens are placed, return true

if (row >= N)

return true;

// Try placing a queen in all columns of the current row

for (int col = 0; col < N; col++) {

if (isSafe(board, row, col)) {

// Place the queen

board[row][col] = 1;

// Recursively place the rest of the queens

if (solveNQueensUtil(board, row + 1))

return true;

// If placing queen in board[row][col] doesn't lead to a solution,


// then backtrack and remove the queen

board[row][col] = 0;

// If no column is safe for the current row, return false

return false;

// Main function to solve the N-Queens problem

bool solveNQueens() {

int board[N][N] = {0}; // Initialize the chessboard with all 0s

if (!solveNQueensUtil(board, 0)) {

printf("Solution does not exist\n");

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>

// Global variables to keep track of the maximum profit

int maxProfit = 0;

// Function to calculate the maximum of two integers

int max(int a, int b) {

return (a > b) ? a : b;

// Backtracking function to solve the knapsack problem

// Parameters:

// wt[]: Weights of items

// val[]: Values of items

// n: Number of items

// W: Capacity of the knapsack

// currWeight: Current weight of the knapsack

// currProfit: Current profit of the knapsack

// index: Index of the current item being considered

void knapsackBacktrack(int W, int wt[], int val[], int n, int currWeight, int currProfit, int index) {

// If the current weight exceeds the knapsack capacity, return

if (currWeight > W) {

return;
}

// Update the maximum profit if the current profit is greater

if (currProfit > maxProfit) {

maxProfit = currProfit;

// If all items are considered, return

if (index == n) {

return;

// Consider including the current item (take the item)

knapsackBacktrack(W, wt, val, n, currWeight + wt[index], currProfit + val[index], index + 1);

// Consider excluding the current item (don't take the item)

knapsackBacktrack(W, wt, val, n, currWeight, currProfit, index + 1);

int main() {

int val[] = {60, 100, 120}; // Values of items

int wt[] = {10, 20, 30}; // Weights of items

int W = 50; // Capacity of the knapsack

int n = sizeof(val) / sizeof(val[0]); // Number of items

// Call the backtracking function

knapsackBacktrack(W, wt, val, n, 0, 0, 0);

// Print the maximum profit

printf("Maximum profit: %d\n", maxProfit);


return 0;

OUTPUT:

Maximum profit: 220

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>

#define N 4 // Number of cities

// Function to calculate the lower bound on the path cost

int calculateCost(int adjMatrix[N][N], int currPath[], int level) {

int cost = 0;

// Adding the cost of edges in the current partial tour

for (int i = 0; i < level - 1; i++) {

cost += adjMatrix[currPath[i]][currPath[i + 1]];

return cost;

// Function to find the minimum cost edge from a given node

int findMinCostEdge(int adjMatrix[N][N], int i) {

int minCost = INT_MAX;

for (int j = 0; j < N; j++) {

if (adjMatrix[i][j] < minCost && i != j) {


minCost = adjMatrix[i][j];

return minCost;

// Branch and Bound function to solve the TSP

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) {

// Add the cost of returning to the starting city

currCost += adjMatrix[currPath[level - 1]][currPath[0]];

// If the current cost is less than the best-known cost, update the solution

if (currCost < *minCost) {

*minCost = currCost;

for (int i = 0; i < N; i++) {

bestPath[i] = currPath[i];

return;

// Explore all unvisited cities and calculate the costs

for (int i = 0; i < N; i++) {

if (!visited[i]) {

visited[i] = true;

currPath[level] = i;
// Calculate the cost of adding this node to the path

int tempCost = currCost + adjMatrix[currPath[level - 1]][i];

// Calculate the lower bound to decide if we should continue exploring this path

int lowerBound = tempCost + findMinCostEdge(adjMatrix, i);

// Proceed only if the current cost is promising (i.e., less than the best-known cost)

if (lowerBound < *minCost) {

branchAndBoundTSP(adjMatrix, currPath, visited, level + 1, tempCost, minCost, bestPath);

// Backtrack: unmark the city as visited

visited[i] = false;

int main() {

// Example adjacency matrix (cost of travel between cities)

int adjMatrix[N][N] = {

{ 0, 10, 15, 20 },

{ 10, 0, 35, 25 },

{ 15, 35, 0, 30 },

{ 20, 25, 30, 0 }

};

// Array to store the current path and the best path found

int currPath[N + 1];

int bestPath[N + 1];


// Array to keep track of visited cities

bool visited[N] = { false };

// Initialize the minimum cost as infinity

int minCost = INT_MAX;

// Start with the first city

visited[0] = true;

currPath[0] = 0;

// Call the branch and bound function to find the minimum cost path

branchAndBoundTSP(adjMatrix, currPath, visited, 1, 0, &minCost, bestPath);

// Print the best path and its cost

printf("Minimum cost: %d\n", minCost);

printf("Best path: ");

for (int i = 0; i < N; i++) {

printf("%d ", bestPath[i]);

printf("%d\n", bestPath[0]); // Print return to the starting city

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.

You might also like