Experiment-8:
WAP that implements the Heap sort and Priority Queue using Heap:
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100 // Maximum size of the heap
// Structure to represent a max heap
typedef struct {
int arr[MAX_SIZE];
int size;
} MaxHeap;
// Function to swap two elements
void swap(int *x, int *y) {
int temp = *x;
*x = *y;
*y = temp;
}
// Function to heapify a subtree rooted at index `i`
void maxHeapify(MaxHeap *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);
}
}
// Function to insert a new key into the max heap
void insert(MaxHeap *heap, int key) {
if (heap->size == MAX_SIZE)
{printf("Heap overflow\n");
return;
}
// Insert the new key at the end and increase the heap size
int i = heap->size++;
heap->arr[i] = key;
// Fix the max heap property if it is violated
while (i != 0 && heap->arr[(i - 1) / 2] < heap->arr[i])
{swap(&heap->arr[i], &heap->arr[(i - 1) / 2]);
i = (i - 1) / 2;
}
}
// Function to get the maximum element (root) from the max heap
int getMax(MaxHeap *heap) {
if (heap->size <= 0)
{ printf("Heap is
empty\n");return -1;
}
return heap->arr[0];
}
// Function to extract the maximum element (root) from the max heap
int extractMax(MaxHeap *heap) {
if (heap->size <= 0)
{ printf("Heap is
empty\n");return -1;
}
int root = heap->arr[0];
heap->arr[0] = heap->arr[--heap->size];
maxHeapify(heap, 0);
return root;
}
// Function to increase the key at index `i` to new_key
void increaseKey(MaxHeap *heap, int i, int new_key) {
if (i < 0 || i >= heap->size || heap->arr[i] > new_key)
{printf("Invalid operation\n");
return;
}
heap->arr[i] = new_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;
}
}
// Function to delete a key at index `i`
void deleteKey(MaxHeap *heap, int i) {
increaseKey(heap, i, INT_MAX ); // Increase key to infinity
extractMax(heap); // Extract the maximum
}
// Heap Sort function
void heapSort(int arr[], int n)
{MaxHeap heap;
[Link] = 0;
// Insert all elements into the heap
for (int i = 0; i < n; i++)
insert(&heap, arr[i]);
// Extract elements from heap in sorted order
for (int i = n - 1; i >= 0; i--)
arr[i] = extractMax(&heap);
}
// Function to display an array
void displayArray(int arr[], int n) {
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
// Main function to test the above code
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = sizeof(arr) / sizeof(arr[0]);
printf("Original array: ");
displayArray(arr, n);
// Heap Sort
heapSort(arr, n);
printf("Sorted array using Heap Sort: ");
displayArray(arr, n);
// Priority Queue operations
MaxHeap heap;
[Link] = 0;
insert(&heap, 3);
insert(&heap, 10);
insert(&heap, 15);
insert(&heap, 7);
printf("Max element in the priority queue: %d\n", getMax(&heap));
printf("Extracting max: %d\n", extractMax(&heap));
printf("Max element after extraction: %d\n", getMax(&heap));
return 0;
}
Output:
Experiment-9:
Write a program that implements the Merge sort.
#include <iostream>
using namespace std;
void merge(int arr[], int left, int mid, int right)
{int n1 = mid - left + 1;
int n2 = right - mid;
int leftArr[n1], rightArr[n2];
for (int i = 0; i < n1; i++)
leftArr[i] = arr[left + i];
for (int j = 0; j < n2; j++)
rightArr[j] = arr[mid + 1 + j];
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (leftArr[i] <= rightArr[j])
{arr[k] = leftArr[i];
i++;
} else {
arr[k] = rightArr[j];
j++;
}
k++;
}
while (i < n1)
{ arr[k] =
leftArr[i];i++;
k++;
}
while (j < n2) {
arr[k] = rightArr[j];
j++;
k++;
}
}
void mergeSort(int arr[], int left, int right)
{if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
void printArray(int arr[], int size)
{for (int i = 0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
}
int main() {
int arr[] = {38, 27, 43, 3, 9, 82, 10};
int size = sizeof(arr) / sizeof(arr[0]);
cout << "Original array: ";
printArray(arr, size);
mergeSort(arr, 0, size - 1);
cout << "Sorted array: ";
printArray(arr, size);
return 0;
}
Output:
Experiment-10:
Write a program that implements the Quick sort.
#include <iostream>
using namespace std;
void swap(int *a, int *b)
{int temp = *a;
*a = *b;
*b = temp;
}
int partition(int *A, int p, int r)
{int i = p, j = p;
while (j < r) {
if (A[j] < A[r]) {
swap(&A[i], &A[j]);
i++;
}
j++;
}
swap(&A[i], &A[r]);
return i;
}
void QuickSort(int *A, int p, int r)
{if (p < r) {
int q = partition(A, p, r);
QuickSort(A, p, q - 1);
QuickSort(A, q + 1, r);
}}
int main() {
int A[] = {34, 56, 23, 1, 2, 0, -1, 7, 22, 100, 21};
int r = sizeof(A) / sizeof(A[0]) - 1;
QuickSort(A, 0, r);
for (int i = 0; i <= r; i++)
{cout << A[i] << "\t";}
cout << endl;
return 0;}
Output:
Experiment-11:
Write a program that implements the Hashing using different methods.
#include <iostream>
using namespace std;
const int TABLE_SIZE = 10;
class LinearProbingHash {
int *table;
public:
LinearProbingHash() {
table = new int[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = -1; // -1 indicates an empty slot
}
void insert(int key) {
int hash = key % TABLE_SIZE;
int originalHash = hash;
while (table[hash] != -1) {
hash = (hash + 1) % TABLE_SIZE;
if (hash == originalHash) {
cout << "Table is full" << endl;
return;
}
}
table[hash] = key;
}
void display() {
cout << "Linear Probing Table: ";
for (int i = 0; i < TABLE_SIZE; i++)
cout << table[i] << " ";
cout << endl;
}
};
class QuadraticProbingHash
{int *table;
public:
QuadraticProbingHash() {
table = new int[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = -1;
}
void insert(int key) {
int hash = key % TABLE_SIZE;
int i = 0;
while (table[(hash + i * i) % TABLE_SIZE] != -1)
{i++;
if (i == TABLE_SIZE) {
cout << "Table is full" << endl;
return;
}
}
table[(hash + i * i) % TABLE_SIZE] = key;
}
void display() {
cout << "Quadratic Probing Table: ";
for (int i = 0; i < TABLE_SIZE; i++)
cout << table[i] << " ";
cout << endl;
}
};
class DoubleHashingHash
{int *table;
int PRIME;
public:
DoubleHashingHash() {
table = new int[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = -1;
PRIME = 7;
}
int hash1(int key) {
return key % TABLE_SIZE;
}
int hash2(int key) {
return PRIME - (key % PRIME);
}
void insert(int key) {
int hash = hash1(key);
int stepSize = hash2(key);
int i = 0;
while (table[(hash + i * stepSize) % TABLE_SIZE] != -1)
{i++;
if (i == TABLE_SIZE) {
cout << "Table is full" << endl;
return;
}
}
table[(hash + i * stepSize) % TABLE_SIZE] = key;
}
void display() {
cout << "Double Hashing Table: ";
for (int i = 0; i < TABLE_SIZE; i++)
cout << table[i] << " ";
cout << endl;
}
};
int main() {
int keys[] = {23, 43, 13, 27, 10, 33, 19, 29, 25, 17};
int n = sizeof(keys) / sizeof(keys[0]);
LinearProbingHash linearHash;
QuadraticProbingHash quadraticHash;
DoubleHashingHash doubleHash;
for (int i = 0; i < n; i++)
{ [Link](keys[i]);
[Link](keys[i]);
[Link](keys[i]);
}
[Link]();
[Link]();
[Link]();
return 0;
}
Output:
Experiment-12:
Write a program that implements the disjoint set using link list structure and rootedtree.
include <iostream>
#include <unordered_map>
using namespace std;
class Node
{public:
int data;
Node* parent;
int rank; // Used for union by rank in the tree approach
Node(int data)
{ this->data =
data;
this->parent = this; // Initially, a node is its own parent
this->rank = 0; // Initial rank is zero
}
};
// Disjoint Set using Linked List and Rooted Tree
class DisjointSet {
unordered_map<int, Node*> map;
public:
// Creates a new set with a single element
void makeSet(int data) {
if ([Link](data) != [Link]()) {
cout << "Element " << data << " already exists." << endl;
return;
}
Node* newNode = new Node(data);
map[data] = newNode;
cout << "Set created for element " << data << "." << endl;
}
// Finds the representative (root) of the set containing the element
Node* findSet(int data) {
if ([Link](data) == [Link]()) {
cout << "Element " << data << " not found in any set." << endl;
return nullptr;
}
return findSet(map[data]);
}
// Helper function for findSet with path compression
Node* findSet(Node* node) {
if (node->parent == node)
{ return node; // Root node
found
}
node->parent = findSet(node->parent); // Path compression
return node->parent;
}
// Union of two sets using union by rank
void unionSets(int data1, int data2) {
Node* node1 = findSet(data1);
Node* node2 = findSet(data2);
if (node1 == nullptr || node2 == nullptr) {
cout << "One or both elements not found in any set." << endl;
return;
}
if (node1 == node2) {
cout << "Both elements are in the same set." << endl;
return;
}
// Union by rank
if (node1->rank > node2->rank)
{node2->parent = node1;
} else if (node1->rank < node2->rank)
{node1->parent = node2;
} else {
node2->parent = node1;
node1->rank++;
}
cout << "Sets containing " << data1 << " and " << data2 << " have been merged." << endl;
}
// Display the representative of each set
void displaySets() {
cout << "Current sets and their representatives:" << endl;
for (auto pair : map) {
int element = [Link];
Node* rep = findSet(element);
if (rep) {
cout << "Element " << element << " belongs to set with representative " << rep->data << endl;
}}}};
int main()
{ DisjointSet ds;
// Create sets for individual elements
[Link](1);
[Link](2);
[Link](3);
[Link](4);
[Link](5);
// Display sets before any unions
cout << "\nSets before union operations:" << endl;
[Link]();
// Perform union operations
[Link](1, 2);
[Link](3, 4);
[Link](2, 3);
// Display sets after union operations
cout << "\nSets after union operations:" << endl;
[Link]();
// Find representatives for individual elements
cout << "\nFinding representatives:" << endl;
cout << "Representative of 1: " << [Link](1)->data << endl;
cout << "Representative of 3: " << [Link](3)->data << endl;
cout << "Representative of 5: " << [Link](5)->data << endl;
return 0;}
Output:
Experiment-13:
Write a program that implements the BFS and DFS
#include <iostream>
#include <list>
#include <queue>
#include <stack>
#include <vector>
using namespace std;
class Graph {
int vertices; // Number of vertices in the graph
vector<list<int>> adjList; // Adjacency list
public:
// Constructor
Graph(int vertices) {
this->vertices = vertices;
[Link](vertices);
}
// Add edge to the graph
void addEdge(int u, int v) {
adjList[u].push_back(v); // Add v to u's list
adjList[v].push_back(u); // Since the graph is undirected
}
// Breadth-First Search (BFS)
void BFS(int start) {
vector<bool> visited(vertices, false);
queue<int> q;
visited[start] = true;
[Link](start);
cout << "BFS starting from vertex " << start << ": ";
while (![Link]()) {
int node = [Link]();
[Link]();
cout << node << " ";
for (auto neighbor : adjList[node])
{if (!visited[neighbor]) {
visited[neighbor] = true;
[Link](neighbor);
}} }
cout << endl;
}
// Depth-First Search (DFS) - Recursive helper
void DFSUtil(int node, vector<bool> &visited) {
visited[node] = true;
cout << node << " ";
for (auto neighbor : adjList[node])
{if (!visited[neighbor]) {
DFSUtil(neighbor, visited);
}}}
// Depth-First Search (DFS) - Main function
void DFS(int start) {
vector<bool> visited(vertices, false);
cout << "DFS starting from vertex " << start << ": ";
DFSUtil(start, visited);
cout << endl;
}};
int main()
{ Graph
g(6);
// Add edges
[Link](0, 1);
[Link](0, 2);
[Link](1, 3);
[Link](2, 4);
[Link](3, 5);
[Link](4, 5);
// Perform BFS and DFS
cout << "Performing BFS and DFS on the graph:" << endl;
[Link](0); // Starting BFS from node 0
[Link](0); // Starting DFS from node 0
return 0;
}
Output:
Experiment-14:
Write a program that implements the Minimum Spanning Tree via
a) Prim’s algoruthm.
b) Kruskal algorithm.
Code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <tuple>
#include <climits> // For INT_MAX
using namespace std;
class Graph
{ int
vertices;
vector<vector<pair<int, int>>> adjList; // For Prim's: Adjacency list with {neighbor, weight}
vector<tuple<int, int, int>> edges; // For Kruskal's: List of edges as {weight, u, v}
public:
Graph(int v) : vertices(v)
{[Link](v);
}
// Adds an undirected edge for Prim's adjacency list and Kruskal's edge list
void addEdge(int u, int v, int weight) {
adjList[u].push_back({v, weight});
adjList[v].push_back({u, weight});
edges.push_back({weight, u, v});
}
// Prim's Algorithm for MST
void primMST() {
vector<int> key(vertices, INT_MAX); // Store minimum edge weight for each vertex
vector<int> parent(vertices, -1); // Store MST structure
vector<bool> inMST(vertices, false); // Track vertices included in MST
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
int mstCost = 0; // To store the total cost of the MST
// Starting with vertex 0
key[0] = 0;
[Link]({0, 0});
cout << "Prim's MST edges (u - v):\n";
while (![Link]()) {
int u = [Link]().second;
int weight = [Link]().first;
[Link]();
if (inMST[u]) continue; // If already in MST, skip
inMST[u] = true;
mstCost += weight; // Add the edge weight to the MST cost
for (size_t i = 0; i < adjList[u].size(); i++)
{int v = adjList[u][i].first;
int edgeWeight = adjList[u][i].second;
if (!inMST[v] && edgeWeight < key[v])
{key[v] = edgeWeight;
[Link]({key[v], v});
parent[v] = u;
}}}
// Print MST edges
for (int v = 1; v < vertices; v++)
{if (parent[v] != -1) {
cout << parent[v] << " - " << v << "\n";
}}
cout << "Total Minimum Cost of Prim's MST: " << mstCost << endl;
}
// Find operation for disjoint set (Union-Find) with path compression
int find(int u, vector<int> &parent) {
if (parent[u] != u) {
parent[u] = find(parent[u], parent);
}
return parent[u];
}
// Union operation for disjoint set (Union-Find) with union by rank
void unionSets(int u, int v, vector<int> &parent, vector<int> &rank) {
int rootU = find(u, parent);
int rootV = find(v, parent);
if (rootU != rootV) {
if (rank[rootU] > rank[rootV])
{parent[rootV] = rootU;
} else if (rank[rootU] < rank[rootV])
{parent[rootU] = rootV;
} else {
parent[rootV] = rootU;
rank[rootU]++;
}}}
// Kruskal's Algorithm for MST
void kruskalMST() {
sort([Link](), [Link]()); // Sort edges by weight
vector<int> parent(vertices);
vector<int> rank(vertices, 0);
for (int i = 0; i < vertices; i++) {
parent[i] = i;
}
int mstCost = 0; // To store the total cost of the MST
cout << "Kruskal's MST edges (u - v) with weights:\n";
for (size_t i = 0; i < [Link](); i++) {
int weight = get<0>(edges[i]);
int u = get<1>(edges[i]);
int v = get<2>(edges[i]);
if (find(u, parent) != find(v, parent)) {
cout << u << " - " << v << " : " << weight << "\n";
mstCost += weight; // Add the edge weight to the MST cost
unionSets(u, v, parent, rank);
}}
cout << "Total Minimum Cost of Kruskal's MST: " << mstCost << endl;
}};
int main()
{ Graph
g(6);
// Adding edges
[Link](0, 1, 4);
[Link](0, 2, 4);
[Link](1, 2, 2);
[Link](1, 3, 6);
[Link](2, 3, 8);
[Link](3, 4, 9);
[Link](4, 5, 10);
[Link](3, 5, 2);
cout << "Minimum Spanning Tree using Prim's Algorithm:\n";
[Link]();
cout << "\nMinimum Spanning Tree using Kruskal's Algorithm:\n";
[Link]();
return 0;}
Output:
Experiment-15:
AIM: Write a program that implements the Shortest Path Algorithms via
a. Dijkstra’s
b. Bellman-Ford algorithm.
Code:
#include <iostream>
#include <vector>
#include <climits>
#include <queue>
#include <tuple>
using namespace std;
class Graph {
int vertices; // Number of vertices
vector<vector<pair<int, int>>> adjList; // Adjacency list for Dijkstra's algorithm
public:
Graph(int v) : vertices(v)
{[Link](v);
}
// Function to add edges to the graph
void addEdge(int u, int v, int weight) {
adjList[u].emplace_back(v, weight);
adjList[v].emplace_back(u, weight); // For undirected graph
}
// Dijkstra's Algorithm
void dijkstra(int source) {
vector<int> dist(vertices, INT_MAX); // Distance from source
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; // Min-heap
dist[source] = 0;
[Link]({0, source}); // {distance, vertex}
cout << "Dijkstra's Algorithm:\n";
while (![Link]()) {
int u = [Link]().second; // Get the vertex with the smallest [Link]();
// Traverse all adjacent vertices
for (const auto& neighbor : adjList[u])
{int v = [Link];
int weight = [Link];
// If a shorter path to v is found
if (dist[u] + weight < dist[v])
{dist[v] = dist[u] + weight;
[Link]({dist[v], v})}}}
// Print the result
for (int i = 0; i < vertices; i++) {
cout << "Distance from source to vertex " << i << " is " << dist[i] << endl;
}
}
// Bellman-Ford Algorithm
void bellmanFord(int source) {
vector<int> dist(vertices, INT_MAX);
dist[source] = 0;
cout << "\nBellman-Ford Algorithm:\n";
for (int i = 1; i < vertices; i++) {
for (int u = 0; u < vertices; u++) {
for (const auto& neighbor : adjList[u])
{int v = [Link];
int weight = [Link];
// Relaxation step
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
{dist[v] = dist[u] + weight;
}}}}
// Check for negative-weight cycles
for (int u = 0; u < vertices; u++) {
for (const auto& neighbor : adjList[u])
{int v = [Link];
int weight = [Link];
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
{cout << "Graph contains a negative-weight cycle\n";
return;
}}}
for (int i = 0; i < vertices; i++) {
cout << "Distance from source to vertex " << i << " is " << dist[i] << endl;
}}};
int main() {
Graph g(5); // Create a graph with 5 vertices
[Link](0, 1, 10);[Link](0, 2, 3);[Link](1, 2, 1);[Link](1, 3, 2);[Link](2, 1, 4);
[Link](2, 3, 8);[Link](2, 4, 2);
[Link](3, 4, 7);
g.a ddEdge(4, 3, 9);
int source = 0;
[Link](source);
g.b ellmanFord(source);
return 0;
}
Output: