0% found this document useful (0 votes)
24 views

Assignment No-1

The document contains code to implement sorting algorithms like selection sort, insertion sort, heap sort and radix sort in C/C++/Java and compares their time complexities. It also contains code for Strassen's matrix multiplication algorithm and Dijkstra's shortest path algorithm on graphs.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views

Assignment No-1

The document contains code to implement sorting algorithms like selection sort, insertion sort, heap sort and radix sort in C/C++/Java and compares their time complexities. It also contains code for Strassen's matrix multiplication algorithm and Dijkstra's shortest path algorithm on graphs.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

1.

Write programs in C/C++/ Java to sort a list of n numbers in ascending order using
selection sort, insertion sort, heap sort, radix sort. Determine the time required to sort
and compare on basis of time complexity for different values of n.

#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <algorithm> // for std::swap, std::max_element
#include <cmath> // for log10
// Selection Sort
void selectionSort(std::vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n - 1; ++i) {
int minIndex = i;
for (int j = i + 1; j < n; ++j) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
std::swap(arr[i], arr[minIndex]);
}
}
// Insertion Sort
void insertionSort(std::vector<int>& arr) {
int n = arr.size();
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
--j;
}
arr[j + 1] = key;
}
}
// Heap Sort
void heapify(std::vector<int>& arr, int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] > arr[largest]) {
largest = left;
}
if (right < n && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {
std::swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heapSort(std::vector<int>& arr) {
int n = arr.size();
// Build the heap
for (int i = n / 2 - 1; i >= 0; --i) {
heapify(arr, n, i);
}
// Sort by extracting elements from the heap
for (int i = n - 1; i >= 0; --i) {
std::swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
// Radix Sort
void countSort(std::vector<int>& arr, int exp) {
int n = arr.size();
std::vector<int> output(n);
int count[10] = {0};
// Counting occurrences of digits at current exp
for (int i = 0; i < n; ++i) {
int index = (arr[i] / exp) % 10;
count[index]++;
}
// Accumulate counts
for (int i = 1; i < 10; ++i) {
count[i] += count[i - 1];
}
// Build the output array using the accumulated counts
for (int i = n - 1; i >= 0; --i) {
int index = (arr[i] / exp) % 10;
output[--count[index]] = arr[i];
}
// Copy output array back to original array
for (int i = 0; i < n; ++i) {
arr[i] = output[i];
}
}
void radixSort(std::vector<int>& arr) {
int maxVal = *std::max_element(arr.begin(), arr.end());
for (int exp = 1; maxVal / exp > 0; exp *= 10) {
countSort(arr, exp);
}
}
// Helper Functions
void fillWithRandom(std::vector<int>& arr, int range) {
for (int& num : arr) {
num = std::rand() % range;
}
}
void testSort(void (*sortFunction)(std::vector<int>&), const std::string& sortName, int n, int range) {
std::vector<int> arr(n);
fillWithRandom(arr, range);
clock_t start = clock();
sortFunction(arr);
clock_t end = clock();
double timeTaken = double(end - start) / CLOCKS_PER_SEC;
std::cout << "Time taken for " << sortName << " with " << n << " elements: "
<< timeTaken << " seconds." << std::endl;
}
int main() {
std::srand(std::time(nullptr)); // Seed for random generator
int range = 10000; // Range for random numbers
// Test with different values of `n`
std::vector<int> testValues = {1000, 5000, 10000};
std::cout << "Testing selection sort:\n";
for (int n : testValues) {
testSort(selectionSort, "selection sort", n, range);
}
std::cout << "\nTesting insertion sort:\n";
for (int n : testValues) {
testSort(insertionSort, "insertion sort", n, range);
}
std::cout << "\nTesting heap sort:\n";
for (int n : testValues) {
testSort(heapSort, "heap sort", n, range);
}
std::cout << "\nTesting radix sort:\n";
for (int n : testValues) {
testSort(radixSort, "radix sort", n, range); }
return 0;
}
2. Write a program in C/C++/ Java to implement Strassen‟s Matrix multiplication

#include <iostream>
#include <vector>
#include <cmath>

// Function to add two matrices


std::vector<std::vector<int>> matrixAdd(const std::vector<std::vector<int>>& A, const
std::vector<std::vector<int>>& B) {
int n = A.size();
std::vector<std::vector<int>> result(n, std::vector<int>(n));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
result[i][j] = A[i][j] + B[i][j];
}
}
return result;
}

// Function to subtract two matrices


std::vector<std::vector<int>> matrixSubtract(const std::vector<std::vector<int>>& A, const
std::vector<std::vector<int>>& B) {
int n = A.size();
std::vector<std::vector<int>> result(n, std::vector<int>(n));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
result[i][j] = A[i][j] - B[i][j];
}
}
return result;
}

// Strassen's Matrix Multiplication Algorithm


std::vector<std::vector<int>> strassenMultiply(const std::vector<std::vector<int>>& A, const
std::vector<std::vector<int>>& B) {
int n = A.size();

if (n == 1) {
return {{A[0][0] * B[0][0]}};
}

// Split matrices into quadrants


int mid = n / 2;
std::vector<std::vector<int>> A11(mid, std::vector<int>(mid));
std::vector<std::vector<int>> A12(mid, std::vector<int>(mid));
std::vector<std::vector<int>> A21(mid, std::vector<int>(mid));
std::vector<std::vector<int>> A22(mid, std::vector<int>(mid));
std::vector<std::vector<int>> B11(mid, std::vector<int>(mid));
std::vector<std::vector<int>> B12(mid, std::vector<int>(mid));
std::vector<std::vector<int>> B21(mid, std::vector<int>(mid));
std::vector<std::vector<int>> B22(mid, std::vector<int>(mid));

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


for (int j = 0; j < mid; ++j) {
A11[i][j] = A[i][j];
A12[i][j] = A[i][j + mid];
A21[i][j] = A[i + mid][j];
A22[i][j] = A[i + mid][j + mid];
B11[i][j] = B[i][j];
B12[i][j] = B[i][j + mid];
B21[i][j] = B[i + mid][j];
B22[i][j] = B[i + mid][j + mid];
}
}
// Strassen's 7 products
std::vector<std::vector<int>> M1 = strassenMultiply(matrixAdd(A11, A22), matrixAdd(B11, B22)); //
M1 = (A11 + A22) * (B11 + B22)
std::vector<std::vector<int>> M2 = strassenMultiply(matrixAdd(A21, A22), B11); // M2 = (A21 +
A22) * B11
std::vector<std::vector<int>> M3 = strassenMultiply(A11, matrixSubtract(B12, B11)); // M3 = A11 *
(B12 - B11)
std::vector<std::vector<int>> M4 = strassenMultiply(A22, matrixSubtract(B21, B11)); // M4 = A22 *
(B21 - B11)
std::vector<std::vector<int>> M5 = strassenMultiply(matrixAdd(A11, A12), B22); // M5 = (A11 +
A12) * B22
std::vector<std::vector<int>> M6 = strassenMultiply(matrixSubtract(A21, A11), matrixAdd(B11,
B12)); // M6 = (A21 - A11) * (B11 + B12)
std::vector<std::vector<int>> M7 = strassenMultiply(matrixSubtract(A12, A22), matrixAdd(B21,
B22)); // M7 = (A12 - A22) * (B21 + B22)
// Reconstruct the results into four quadrants
std::vector<std::vector<int>> C11 = matrixAdd(matrixSubtract(matrixAdd(M1, M4), M5), M7); //
C11 = M1 + M4 - M5 + M7
std::vector<std::vector<int>> C12 = matrixAdd(M3, M5); // C12 = M3 + M5
std::vector<std::vector<int>> C21 = matrixAdd(M2, M4); // C21 = M2 + M4
std::vector<std::vector<int>> C22 = matrixAdd(matrixSubtract(matrixAdd(M1, M3), M2), M6); //
C22 = M1 + M3 - M2 + M6
// Combine the quadrants to form the resultant matrix
std::vector<std::vector<int>> result(n, std::vector<int>(n));
for (int i = 0; i < mid; ++i) {
for (int j = 0; j < mid; ++j) {
result[i][j] = C11[i][j];
result[i][j + mid] = C12[i][j];
result[i + mid][j] = C21[i][j];
result[i + mid][j + mid] = C22[i][j];
}
}
return result;
}
// Print matrix function
void printMatrix(const std::vector<std::vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
std::cout << matrix[i][j] << " ";
}
std::cout << std::endl;
}
}
int main() {
// Example matrices to multiply
std::vector<std::vector<int>> A = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
std::vector<std::vector<int>> B = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
// Use Strassen's algorithm to multiply the matrices
std::vector<std::vector<int>> C = strassenMultiply(A, B);
// Print the result
std::cout << "Result of Strassen's Matrix Multiplication:\n";
printMatrix(C);

return 0;
}
3. Write a program in C/C++/ Java to from a given vertex in a weighted connected
graph, find shortest paths to other vertices using Dijikstra‟s algorithm

#include <iostream>
#include <vector>
#include <queue>
#include <limits> // for std::numeric_limits
#include <utility> // for std::pair

// Define a structure to represent the graph


struct Edge {
int destination;
int weight;
};

using AdjacencyList = std::vector<std::vector<Edge>>;

// Utility function to add an edge to the graph


void addEdge(AdjacencyList& graph, int source, int destination, int weight) {
graph[source].push_back({destination, weight});
graph[destination].push_back({source, weight}); // For undirected graph
}

// Dijkstra's Algorithm
std::vector<int> dijkstra(const AdjacencyList& graph, int source) {
int n = graph.size();
std::vector<int> distances(n, std::numeric_limits<int>::max());
std::vector<bool> visited(n, false);

// Priority queue to select the vertex with the minimum distance


std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<>> pq;

distances[source] = 0;
pq.push({0, source});

while (!pq.empty()) {
int currentDistance = pq.top().first;
int currentVertex = pq.top().second;
pq.pop();

if (visited[currentVertex]) {
continue;
}
visited[currentVertex] = true;

// Relax the edges from the current vertex


for (const Edge& edge : graph[currentVertex]) {
int neighbor = edge.destination;
int weight = edge.weight;

if (currentDistance + weight < distances[neighbor]) {


distances[neighbor] = currentDistance + weight;
pq.push({distances[neighbor], neighbor});
}
}
}

return distances;
}

// Main function to demonstrate Dijkstra's Algorithm


int main() {
int n = 6; // Number of vertices
AdjacencyList graph(n);

// Define the edges of the graph


addEdge(graph, 0, 1, 7);
addEdge(graph, 0, 2, 9);
addEdge(graph, 0, 5, 14);
addEdge(graph, 1, 2, 10);
addEdge(graph, 1, 3, 15);
addEdge(graph, 2, 3, 11);
addEdge(graph, 2, 5, 2);
addEdge(graph, 3, 4, 6);
addEdge(graph, 4, 5, 9);

int sourceVertex = 0; // Source vertex for shortest path calculation


std::vector<int> shortestPaths = dijkstra(graph, sourceVertex);

std::cout << "Shortest paths from vertex " << sourceVertex << ":\n";
for (int i = 0; i < n; ++i) {
std::cout << "To vertex " << i << ": " << shortestPaths[i] << std::endl;
}

return 0;
}
4. Write a program in C/C++/ Java to implement Knapsack problems using Greedy
method

#include <iostream>
#include <vector>
#include <algorithm>

// Define a structure to represent an item with weight and value


struct Item {
int weight;
int value;

// Calculate value-to-weight ratio


double valuePerWeight() const {
return static_cast<double>(value) / weight;
}
};

// Comparator to sort items based on their value-to-weight ratio (descending order)


bool comparator(const Item& a, const Item& b) {
return a.valuePerWeight() > b.valuePerWeight();
}

// Greedy approach for Fractional Knapsack


double fractionalKnapsack(const std::vector<Item>& items, int capacity) {
std::vector<Item> sortedItems = items;
std::sort(sortedItems.begin(), sortedItems.end(), comparator); // Sort items by value-to-weight
ratio

double totalValue = 0.0;


int currentCapacity = capacity;

for (const Item& item : sortedItems) {


if (currentCapacity == 0) {
break; // Knapsack is full
}

if (item.weight <= currentCapacity) {


// If the whole item can fit, add its value and reduce capacity
totalValue += item.value;
currentCapacity -= item.weight;
} else {
// If not, take as much as possible (fractional)
double fraction = static_cast<double>(currentCapacity) / item.weight;
totalValue += item.value * fraction;
currentCapacity = 0; // Knapsack is now full
}
}

return totalValue;
}

// Main function to demonstrate the Fractional Knapsack with the Greedy method
int main() {
// Example items with weight and value
std::vector<Item> items = {
{10, 60}, // 10 kg, 60 value
{20, 100}, // 20 kg, 100 value
{30, 120}, // 30 kg, 120 value
};

int capacity = 50; // Maximum capacity of the knapsack in kg

double maxValue = fractionalKnapsack(items, capacity);

std::cout << "Maximum value achievable with a capacity of " << capacity << " is " << maxValue << "."
<< std::endl;

return 0;
}
5. Write a program in C/C++/ Java to implement optimal binary search tree and also
calculate the best case and worst case complexity.

#include <iostream>
#include <vector>
#include <limits>
#include <iomanip> // for std::setw

// Utility function to construct the optimal BST


void constructOptimalBST(
const std::vector<std::vector<int>>& rootMatrix,
int i,
int j,
int level,
const std::vector<std::string>& keys,
std::vector<std::string>& bst
){
if (i > j) {
return; // No more nodes to construct
}

int rootIndex = rootMatrix[i][j];


std::string rootKey = keys[rootIndex];
bst.push_back(std::string(level, ' ') + rootKey);

// Construct left and right subtrees recursively


constructOptimalBST(rootMatrix, i, rootIndex - 1, level + 1, keys, bst);
constructOptimalBST(rootMatrix, rootIndex + 1, j, level + 1, keys, bst);
}

// Optimal Binary Search Tree construction with dynamic programming


void optimalBST(
const std::vector<std::string>& keys,
const std::vector<float>& probabilities,
const std::vector<float>& frequencies,
std::vector<std::string>& bst
){
int n = keys.size();
std::vector<std::vector<float>> cost(n + 1, std::vector<float>(n + 1, 0));
std::vector<std::vector<float>> sumFrequencies(n + 1, std::vector<float>(n + 1, 0));
std::vector<std::vector<int>> rootMatrix(n + 1, std::vector<int>(n + 1, 0));

// Compute the sum of frequencies for each subarray


for (int i = 0; i < n; ++i) {
sumFrequencies[i][i] = frequencies[i];
for (int j = i + 1; j < n; ++j) {
sumFrequencies[i][j] = sumFrequencies[i][j - 1] + frequencies[j];
}
}

// Dynamic programming to calculate the optimal cost and root structure


for (int length = 1; length <= n; ++length) {
for (int i = 0; i <= n - length; ++i) {
int j = i + length - 1;
cost[i][j] = std::numeric_limits<float>::infinity();
for (int r = i; r <= j; ++r) {
float leftCost = (r > i) ? cost[i][r - 1] : 0;
float rightCost = (r < j) ? cost[r + 1][j] : 0;
float totalCost = leftCost + rightCost + sumFrequencies[i][j];
if (totalCost < cost[i][j]) {
cost[i][j] = totalCost;
rootMatrix[i][j] = r;
}
}
}
}

// Construct the optimal BST using the root matrix


constructOptimalBST(rootMatrix, 0, n - 1, 0, keys, bst);
}

// Utility function to print a 2D vector for debugging


void printMatrix(const std::vector<std::vector<float>>& matrix) {
for (const auto& row : matrix) {
for (float value : row) {
if (std::isinf(value)) {
std::cout << std::setw(8) << "INF ";
} else {
std::cout << std::setw(8) << value << " ";
}
}
std::cout << std::endl;
}
}

// Main function to demonstrate the Optimal BST construction


int main() {
std::vector<std::string> keys = {"A", "B", "C", "D"};
std::vector<float> probabilities = {0.1f, 0.2f, 0.4f, 0.3f};
std::vector<float> frequencies = {0.1f, 0.2f, 0.4f, 0.3f}; // Frequency of each key

std::vector<std::string> bst;
optimalBST(keys, probabilities, frequencies, bst);

std::cout << "Optimal BST structure:" << std::endl;


for (const auto& line : bst) {
std::cout << line << std::endl;
}

return 0;
}

You might also like