Download as pdf or txt
Download as pdf or txt
You are on page 1of 10

1.

Problem Name: Sorting a List using Selection Sort


Analysis:
Selection Sort is a simple sorting algorithm that iteratively finds the smallest element from the unsorted portion of the list and swaps it with the first unsorted element. Despite its simplicity, it has a time
complexity of O(n^2), making it inefficient for larger lists.
Algorithm:
procedure selectionSort(A : list of sortable items)
n = length(A)
for i = 0 to n - 2
minIndex = i
for j = i + 1 to n - 1
if A[j] < A[minIndex]
minIndex = j
swap A[i] and A[minIndex]
end for
end procedure
Source code:
#include <iostream>
using namespace std;
void selectionSort(int arr[], int n)
{
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]);
}
}
int main()
{
int n;
cout<<"Enter size of array :";
cin>>n;
int arr[n+5];
cout << "Original array: ";
for (int i = 0; i < n; ++i)
{
cin>>arr[i];
}
selectionSort(arr, n);
std::cout << "\nSorted array: ";
for (int i = 0; i < n; ++i)
{
std::cout << arr[i] << " ";
}
return 0;
}
Sample input-output:
Enter size of array :5
Original array: 10 5 3 6 1
Sorted array: 1 3 5 6 10
Remarks:
Selection Sort, while simple to implement, is not suitable for sorting large lists due to its O(n^2) time complexity. It's not adaptive or stable, and there are more efficient sorting algorithms available for
practical use. Nevertheless, it's a good starting point for understanding sorting algorithms before moving on to more advanced ones.
2.Problem Name:Sorting an Array using Insertion Sort
Analysis:
Insertion Sort is a simple sorting algorithm that builds the final sorted array one item at a time. It iterates through the array, taking one element at a time and inserting it into its correct position in the already
sorted part of the array. While it's easy to implement and works well for small datasets or partially sorted data, its time complexity of O(n^2) makes it less efficient for large datasets.
Algorithm:
procedure insertionSort(A : list of sortable items)
n = length(A)
for i = 1 to n - 1
currentElement = A[i]
j=i-1
while j >= 0 and A[j] > currentElement
A[j + 1] = A[j]
j=j-1
A[j + 1] = currentElement
end for
end procedure
Source code:
#include<bits/stdc++.h>
using namespace std;
#include <iostream>
void insertionSort(int arr[], int n)
{
for (int i = 1; i < n; ++i)
{
int currentElement = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > currentElement)
{
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = currentElement;
}
}
int main()
{
int n;
cout<<"Enter size of array :";
cin>>n;
int arr[n+5];
cout << "Original array: ";
for (int i = 0; i < n; ++i)
{
cin>>arr[i];
}
insertionSort(arr, n);
cout << "\nSorted array: ";
for (int i = 0; i < n; ++i)
{
cout << arr[i] << " ";
}
return 0;
}
Sample input-output:
Enter size of array :6
Original array: 124 32 52 24 36 22
Sorted array: 22 24 32 36 52 124
Remarks:
Insertion Sort is an elementary sorting algorithm that works by repeatedly taking one element at a time and inserting it into its correct position within the already sorted part of the array. It's easy to understand
and implement, and it performs well for small datasets or nearly sorted data. However, its time complexity of O(n^2) makes it less efficient for large datasets. For larger datasets, more efficient sorting
algorithms like Merge Sort or Quick Sort should be considered.
3.Problem Name:Sorting an Array using Bubble Sort
Analysis:
Bubble Sort is a simple comparison-based sorting algorithm that repeatedly steps through the list to be sorted, compares adjacent elements, and swaps them if they are in the wrong order. It's easy to
understand and implement but is generally inefficient for large datasets due to its quadratic time complexity.
Algorithm:
procedure bubbleSort(A : list of sortable items)
n = length(A)
for i = 0 to n - 2
for j = 0 to n - i - 2
if A[j] > A[j + 1]
swap A[j] and A[j + 1]
end if
end for
end for
end procedure
Source code:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
void bubbleSort(int arr[], int n)
{
for (int i = 0; i < n - 1; ++i)
{
for (int j = 0; j < n - i - 1; ++j)
{
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
}
}
}
}
int main()
{
int n;
cout<<"Enter size of array :";
cin>>n;
int arr[n+5];
cout << "Original array: ";
for (int i = 0; i < n; ++i)
{
cin>>arr[i];
}
bubbleSort(arr, n);
cout << "\nSorted array: ";
for (int i = 0; i < n; ++i)
{
cout << arr[i] << " ";
}
return 0;
}
Sample input-output:
Enter size of array :5
Original array: 5 3 8 2 1
Sorted array: 1 2 3 5 8
Remarks:
Bubble Sort is a basic sorting algorithm that works by repeatedly stepping through the list, comparing adjacent elements, and swapping them if they are in the wrong order. It's inefficient for large datasets
due to its quadratic time complexity. However, its simplicity and ease of implementation make it a good starting point for learning about sorting algorithms. For practical use, more efficient algorithms like
Merge Sort or Quick Sort are recommended.
4.Problem Name:Sorting an Array using Quick Sort
Analysis:
Quick Sort is a highly efficient and widely used sorting algorithm that employs the divide-and-conquer strategy. It works by selecting a "pivot" element and partitioning the array into two sub-arrays:
elements less than the pivot and elements greater than the pivot. This process is recursively applied to the sub-arrays until the entire array is sorted. Quick Sort has an average-case time complexity of O(n log
n), making it one of the fastest sorting algorithms.
Algorithm:
procedure quickSort(A : list of sortable items, low, high)
if low < high
pivotIndex = partition(A, low, high)
quickSort(A, low, pivotIndex - 1)
quickSort(A, pivotIndex + 1, high)
end procedure
procedure partition(A : list of sortable items, low, high)
pivot = A[high]
i = low - 1
for j = low to high - 1
if A[j] < pivot
i=i+1
swap A[i] and A[j]
swap A[i + 1] and A[high]
return i + 1
end procedure
Source code:
#include<bits/stdc++.h>
using namespace std;
#include <iostream>
int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = low - 1;
for (int j = low; j <= high - 1; ++j)
{
if (arr[j] < pivot)
{
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return i + 1;
}

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


{
if (low < high)
{
int pivotIndex = partition(arr, low, high);
quickSort(arr, low, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, high);
}
}
int main()
{
int n;
cout<<"Enter size of array :";
cin>>n;
int arr[n+5];
cout << "Original array: ";
for (int i = 0; i < n; ++i)
{
cin>>arr[i];
}
quickSort(arr, 0, n - 1);
cout << "Sorted array: ";
for (int i = 0; i < n; ++i)
{
cout << arr[i] << " ";
}
return 0;
}

Sample input-output:
Enter size of array :7
Original array: 64 34 25 12 11 22 90
Sorted array: 11 12 22 25 34 64 90
Remarks:
Quick Sort is a highly efficient sorting algorithm that sorts arrays by dividing them into sub-arrays and recursively sorting those sub-arrays. It's widely used in practice due to its average-case time complexity
of O(n log n). However, its performance can degrade to O(n^2) if the pivot selection is not well-balanced. Quick Sort is a staple in the field of algorithms and is often used as a benchmark for comparing the
efficiency of other sorting algorithms.
5.Problem Name:Sorting an Array using Merge Sort
Analysis:Merge Sort is a widely used sorting algorithm known for its efficiency and stability. It follows the divide-and-conquer strategy by dividing the array into two halves, recursively sorting each half,
and then merging the sorted halves back together. Merge Sort has a consistent time complexity of O(n log n), making it efficient for sorting large datasets.
Algorithm:
procedure mergeSort(A : list of sortable items, low, high)
if low < high
mid = (low + high) / 2
mergeSort(A, low, mid)
mergeSort(A, mid + 1, high)
merge(A, low, mid, high)
end procedure
procedure merge(A : list of sortable items, low, mid, high)
n1 = mid - low + 1
n2 = high - mid
create temporary arrays L[0...n1] and R[0...n2]
for i = 0 to n1 - 1
L[i] = A[low + i]
for j = 0 to n2 - 1
R[j] = A[mid + 1 + j]
i=0
j=0
k = low
while i < n1 and j < n2
if L[i] <= R[j]
A[k] = L[i]
i=i+1
else
A[k] = R[j]
j=j+1
k=k+1
while i < n1
A[k] = L[i]
i=i+1
k=k+1
while j < n2
A[k] = R[j]
j=j+1
k=k+1
end procedure
Source code:
#include<bits/stdc++.h>
using namespace std;
#include <iostream>
void merge(int arr[], int low, int mid, int high)
{
int n1 = mid - low + 1;
int n2 = high - mid;
int L[n1], R[n2];
for (int i = 0; i < n1; ++i)
{
L[i] = arr[low + i];
}
for (int j = 0; j < n2; ++j)
{
R[j] = arr[mid + 1 + j];
}
int i = 0, j = 0, k = low;
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++;
}
}
void mergeSort(int arr[], int low, int high)
{
if (low < high)
{
int mid = low + (high - low) / 2;
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);
merge(arr, low, mid, high);
}
}
int main()
{
int n;
cout<<"Enter size of array :";
cin>>n;
int arr[n+5];
cout << "Original array: ";
for (int i = 0; i < n; ++i)
{
cin>>arr[i];
}
mergeSort(arr, 0, n - 1);
cout << "Sorted array: ";
for (int i = 0; i < n; ++i)
{
cout << arr[i] << " ";
}
return 0;
}
Sample input-output:
Enter size of array :8
Original array: 12 34 62 54 12 33 85 10
Sorted array: 10 12 12 33 34 54 62 85
Remarks:
Merge Sort efficiently sorts arrays by dividing them into sub-arrays, sorting the sub-arrays, and then merging them back together. It has a consistent time complexity of O(n log n), making it one of the most
efficient sorting algorithms. Merge Sort is often used in situations where stability and consistent performance are required. It's also used as the basis for other sorting algorithms, such as Tim Sort.
6.Problem Name:sorting an array using radix sort.
Analysis:
Radix Sort is a non-comparative sorting algorithm that sorts integers by processing individual digits. It starts from the least significant digit (LSB) and works its way to the most significant digit (MSB),
repeatedly using a stable sorting algorithm (usually counting sort) to sort the elements based on the current digit.
Algorithm:
RADIX_SORT(A, d)
// A is an array to be sorted
// k is the number of digits in the largest element in A
for i ← 1 to k do
Apply a stable sort (such as counting sort) on digit i of array A
End
Source Code:
#include <iostream>
using namespace std;
int getMax(int arr[], int n) {
int max = arr[0];
for (int i = 1; i < n; i++) {
if (arr[i] > max)
max = arr[i]; }
return max;}
void countingSort(int arr[], int n, int exp) {
int output[n];
int count[10] = {0};
for (int i = 0; i < n; i++)
count[(arr[i] / exp) % 10]++;
for (int i = 1; i < 10; i++)
count[i] += count[i - 1];
for (int i = n - 1; i >= 0; i--) {
output[count[(arr[i] / exp) % 10] - 1] = arr[i];
count[(arr[i] / exp) % 10]--;}
for (int i = 0; i < n; i++)
arr[i] = output[i];}
void radixSort(int arr[], int n) {
int max = getMax(arr, n);
for (int exp = 1; max / exp > 0; exp *= 10)
countingSort(arr, n, exp);}
void printArr(int a[], int n) {
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;}
int main() {
int n;
cout << "Enter the number of elements: ";
cin >> n;
int a[n];
cout << "Enter the elements:" << endl;
for (int i = 0; i < n; i++)
cin >> a[i];
cout << "Before sorting: ";
printArr(a, n);
radixSort(a, n);
cout << "After sorting: ";
printArr(a, n);
return 0;}
Sample Input:
6
170 45 75 90 802 24
Sample Output:
Before sorting: 170 45 75 90 802 24
After sorting: 24 45 75 90 170 802
Remarks:Radix Sort has a time complexity of O(d * (n + k)), where d is the number of digits and k is the range of input. It can be efficient for larger datasets when the range of input is not significantly large.
7.Problem: Sorting with Heap Sort
Analysis:
Heap Sort is a comparison-based sorting algorithm that utilizes the properties of a binary heap. A heap is an advanced tree-based data structure used primarily for sorting and implementing priority queues.
They are complete binary trees that have the following features:
Every level is filled except the leaf nodes (nodes without children are called leaves).
Every node has a maximum of 2 children.
All the nodes are as far left as possible, this means that every child is to the left of his parent.
Algorithm:
HeapSort(arr)
BuildMaxHeap(arr)
for i = length(arr) down to 2
swap arr[1] with arr[i]
heap_size[arr] = heap_size[arr] - 1
MaxHeapify(arr, 1)
End
BuildMaxHeap(arr)
heap_size(arr) = length(arr)
for i = length(arr) / 2 down to 1
MaxHeapify(arr, i)
End
MaxHeapify(arr, i)
L = left(i)
R = right(i)
if L ≤ heap_size[arr] and arr[L] > arr[i]
largest = L
else
largest = i
if R ≤ heap_size[arr] and arr[R] > arr[largest]
largest = R
if largest ≠ i
swap arr[i] with arr[largest]
MaxHeapify(arr, largest)
End
Source Code:
#include<iostream>
using namespace std;
void MaxHeapify(int A[], int n, int i) {
int largest = i;
int l = 2 * i;
int r = 2 * i + 1;
if (l <= n && A[l] > A[largest]) {
largest = l;}
if (r <= n && A[r] > A[largest]) {
largest = r; }
if (largest != i) {
swap(A[largest], A[i]);
MaxHeapify(A, n, largest);}}
void heapSort(int A[], int n) {
for (int i = n / 2; i >= 1; i--)
MaxHeapify(A, n, i);
for (int i = n; i >1; i--) {
swap(A[1], A[i]);
MaxHeapify(A, i - 1, 1); }}
void printArray(int A[], int n) {
for (int i = 1; i <= n; ++i)
cout << A[i] << " ";
cout << "\n";}
int main() {
int n;
cout << "Enter the number of elements: ";
cin >> n;
int A[n + 1];
cout << "Enter " << n << " elements:\n";
for (int i = 1; i <= n; i++)
cin >> A[i];
cout << "Original array:\n";
printArray(A, n);
heapSort(A, n);
cout << "Sorted array:\n";
printArray(A, n);
return 0; }
Sample Input:
4
35 21 95 17
Sample Output:
Before sorting: 35 21 95 17
After sorting: 17 21 35 95
Remarks: Heap Sort has a consistent time complexity of O(n log n), making it efficient for most scenarios. It is an in-place sorting algorithm that doesn't require additional memory space. Heaps generally
take more time to compute.
8.Problem Name: Solving the Tower of Hanoi Puzzle
Analysis:
The Tower of Hanoi is a classic problem in computer science and mathematics. It involves moving a stack of discs from one peg to another, with the constraint that only one disc can be moved at a time, and
a larger disc cannot be placed on top of a smaller disc. The problem can be solved recursively, and the number of moves required follows the pattern 2^n - 1, where n is the number of discs.
Algorithm (Pseudo Code):
procedure towerOfHanoi(n, source, auxiliary, destination)
if n > 0
towerOfHanoi(n-1, source, destination, auxiliary)
move disc from source to destination
towerOfHanoi(n-1, auxiliary, source, destination)
end procedure
Source Code (C++):
#include <iostream>
using namespace std;
void towerOfHanoi(int n, char source, char auxiliary, char destination)
{
if (n > 0)
{
towerOfHanoi(n - 1, source, destination, auxiliary);
std::cout << "Move disc " << n << " from " << source << " to " << destination << std::endl;
towerOfHanoi(n - 1, auxiliary, source, destination);
}
}

int main()
{
int n = 3; // Number of discs
towerOfHanoi(n, 'A', 'B', 'C');
return 0;
}
Sample Input/Output:
Input: Number of discs = 3
Output:
Move disc 1 from A to C
Move disc 2 from A to B
Move disc 1 from C to B
Move disc 3 from A to C
Move disc 1 from B to A
Move disc 2 from B to C
Move disc 1 from A to C
Remarks:
The Tower of Hanoi problem is a classic example of recursive problem-solving. The algorithm uses the concept of breaking a larger problem into smaller sub-problems and solving them recursively. The
number of moves required to solve the Tower of Hanoi puzzle for n discs is 2^n - 1, making it an interesting problem for exploring the power of recursion in algorithms.
9.Problem Name: Traversing a Graph using Breadth-First Search
Analysis:
Breadth-First Search (BFS) is a graph traversal algorithm that explores all the vertices of a graph in breadth-first order, i.e., it visits all the vertices at distance 1 from the starting vertex, then all the vertices at
distance 2, and so on. BFS is often used to find the shortest path between two nodes in an unweighted graph.
Algorithm (Pseudo Code):
procedure BFS(graph, start)
create a queue Q
enqueue start into Q
mark start as visited
while Q is not empty
current = dequeue from Q
process current vertex
for each neighbor of current
if neighbor is not visited
mark neighbor as visited
enqueue neighbor into Qend procedure
Source Code :
#include<bits/stdc++.h>
using namespace std;
#include <iostream>
#include <list>
#include <queue>
class Graph
{
int vertices;
std::list<int> *adjacencyList;
public:
Graph(int v);
void addEdge(int v, int w);
void BFS(int start);
};
Graph::Graph(int v)
{
vertices = v;
adjacencyList = new std::list<int>[v];
}
void Graph::addEdge(int v, int w)
{
adjacencyList[v].push_back(w);
}
void Graph::BFS(int start)
{
std::vector<bool> visited(vertices, false);
std::queue<int> q;
visited[start] = true;
q.push(start);
while (!q.empty())
{
int current = q.front();
q.pop();
std::cout << current << " ";
for (int neighbor : adjacencyList[current])
{
if (!visited[neighbor])
{
visited[neighbor] = true;
q.push(neighbor);
}
}
}
}
int main()
{
cout<<"Number of edges :";
int n;
cin>>n;
Graph g(n);
cout<<"enter edges:\n";
for(int i=1;i<n;i++)
{
int a,b;
cin>>a>>b;
g.addEdge(a,b);
}
std::cout << "BFS traversal starting from vertex 0: ";
g.BFS(0);
return 0;
}
Sample Input/Output:
Number of edges :7
enter edges:
01
02
13
14
25
26
BFS traversal starting from vertex 0: 0 1 2 3 4 5 6
Remarks: Breadth-First Search is a fundamental graph traversal algorithm that ensures all vertices at distance d from the starting vertex are visited before moving to vertices at distance d+1. It's widely used
in shortest path algorithms and finding connected components. BFS is particularly effective for unweighted graphs and guarantees the shortest path when all edges have the same weight.
10.Problem name: Implement Depth-First Search (DFS)
Analysis:Depth-First Search is a graph traversal algorithm that explores as far as possible along each branch before backtracking. It uses a stack (or recursion) to keep track of the vertices to be explored and
explores one branch as deeply as possible before moving to the next branch.
Algorithm:
Step 1: SET STATUS = 1 (ready state) for each node in G
Step 2:Push the starting node A on the stack and set its STATUS = 2 (waiting state)
Step 3: Repeat Steps 4 and 5 until STACK is empty
Step 4:Pop the top node N. Process it and set its STATUS = 3 (processed state)
Step 5: Push on the stack all the neighbors of N that are in the ready state (whose STATUS = 1) and set their STATUS = 2 (waiting state)
[END OF LOOP]
Step 6: EXIT
Source Code:
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
void dfs(vector<vector<int>>& graph, int start_vertex) {
int vertices = graph.size();
vector<bool> visited(vertices, false);
stack<int> s;
s.push(start_vertex);
visited[start_vertex] = true;
while (!s.empty()) {
int current_vertex = s.top();
s.pop();
cout << current_vertex << " ";
for (int neighbor : graph[current_vertex]) {
if (!visited[neighbor]) {
s.push(neighbor);
visited[neighbor] = true; }}}}
int main() {
int vertices, edges;
cout << "Enter the number of vertices: ";
cin >> vertices;
cout << "Enter the number of edges: ";
cin >> edges;
vector<vector<int>> graph(vertices);
cout << "Enter the edges (vertex pairs):" << endl;
for (int i = 0; i < edges; i++) {
int u, v;
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u); }
int start_vertex;
cout << "Enter the start vertex: ";
cin >> start_vertex;
cout << "DFS traversal starting from vertex " << start_vertex << ": ";
dfs(graph, start_vertex);
cout << endl;
return 0;}
Sample Input:
5
6
01
02
13
14
24
34
0
Sample Output:
DFS traversal starting from vertex 0: 0 2 4 1 3
Remarks:The DFS algorithm explores the depth of the graph before backtracking. The order of traversal depends on the order in which neighbors are pushed onto the stack.
The time complexity of DFS is O(V + E), where V is the number of vertices and E is the number of edges.
11.Problem Name:Searching for an Element in an Array using Linear Search
Analysis:
Linear Search is a simple searching algorithm that sequentially checks each element of an array to find the desired element. It works for both sorted and unsorted arrays. However, it's not very efficient for
large datasets, as it has a time complexity of O(n), where n is the number of elements in the array.
Algorithm:
procedure linearSearch(arr, target)
for each element in arr
if element equals target
return index of element
return -1 (element not found)
end procedure
Source Code (C++):
#include<bits/stdc++.h>
using namespace std;
#include <iostream>
#include <vector>
int linearSearch(const std::vector<int>& arr, int target)
{
for (int i = 0; i < arr.size(); ++i)
{
if (arr[i] == target)
{
return i;
}
}
return -1; // Element not found
}
int main()
{
int n;
cout<<"Enter size of array :";
cin>>n;
vector<int>arr(n+5,0);
cout << "Original array: ";
for (int i = 0; i <n; ++i)
{
cin>>arr[i];
}
int target;
cout<<" enter target element:";
cin>>target;
int index = linearSearch(arr, target);
if (index != -1)
{
std::cout << "Element " << target << " found at index " << index+1 << std::endl;
}
else
{
std::cout << "Element " << target << " not found in the array" << std::endl;
}
return 0;
}
Sample Input/Output:
Enter size of array :9
Original array: 12 45 67 89 34 56 23 90 11
enter target element:56
Element 56 found at index 6
Remarks:
Linear Search is a basic searching algorithm that's easy to understand and implement. It's suitable for small arrays or situations where the data is not sorted. However, for large datasets, more efficient
algorithms like Binary Search (for sorted arrays) or Hashing are preferred, as they have better average and worst-case time complexities.
12.Problem Name:Implement Matrix Multiplication
Analysis:
Matrix multiplication is the process of multiplying two matrices to obtain a new matrix. It involves taking the dot product of rows and columns of the matrices to compute the elements of the resulting matrix.
Algorithm:
MATRIX MULTIPLICATION(A, B)
Step 1: Initialize result matrix C with dimensions rows_A x cols_B
Step 2: For each row i in A
a. For each column j in B
i. Initialize sum = 0
ii. For k = 0 to cols_A - 1
A. sum += A[i][k] * B[k][j]
iii. Set C[i][j] = sum
[END OF LOOP]
Step 3: Return matrix C
Source Code:
#include<bits/stdc++.h>
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> matrixMultiplication(const vector<vector<int>>& A, const vector<vector<int>>& B)
{
int rows_A = A.size();
int cols_A = A[0].size();
int cols_B = B[0].size();
vector<vector<int>> C(rows_A, vector<int>(cols_B, 0));
for (int i = 0; i < rows_A; i++)
{
for (int j = 0; j < cols_B; j++)
{
int sum = 0;
for (int k = 0; k < cols_A; k++)
{
sum += A[i][k] * B[k][j];
}
C[i][j] = sum;
}
}
return C;
}
int main()
{
int rows_A, cols_A, rows_B, cols_B;
cout << "Enter the dimensions of matrix A (rows cols): ";
cin >> rows_A >> cols_A;
cout << "Enter the dimensions of matrix B (rows cols): ";
cin >> rows_B >> cols_B;
if (cols_A != rows_B)
{
cout << "Matrix multiplication is not possible due to incompatible dimensions." << endl;
return 1;
}
vector<vector<int>> A(rows_A, vector<int>(cols_A));
vector<vector<int>> B(rows_B, vector<int>(cols_B));
cout << "Enter the elements of matrix A:" << endl;
for (int i = 0; i < rows_A; i++)
for (int j = 0; j < cols_A; j++)
cin >> A[i][j];
cout << "Enter the elements of matrix B:" << endl;
for (int i = 0; i < rows_B; i++)
for (int j = 0; j < cols_B; j++)
cin >> B[i][j];
vector<vector<int>> result = matrixMultiplication(A, B);
cout << "Resultant matrix C:" << endl;
for (int i = 0; i < rows_A; i++)
{
for (int j = 0; j < cols_B; j++)
{
cout << result[i][j] << " ";
}
cout << endl;
}
return 0;
}
Sample Input:
32
24
46
68
23
135
246
Sample Output:
Resultant matrix C:
10 20 30
20 40 60
30 60 90
Remarks:Matrix multiplication is a fundamental operation in linear algebra. It's important to ensure that the number of columns in the first matrix matches the number of rows in the second matrix for the
operation to be valid.
13.Problem Name:Analysis Binary Search with an algorithm and sample code.
Analysis:
Binary Search is defined as a searching algorithm used in a sorted array by repeatedly dividing the search interval in half. The idea of binary search is to use the information that the array is sorted and reduce
the time complexity to O(log N).
In this algorithm,
Divide the search space into two halves by finding the middle index “mid”.
Compare the middle element of the search space with the key.
If the key is found at middle element, the process is terminated.
If the key is not found at middle element, choose which half will be used as the next search space.
If the key is smaller than the middle element, then the left side is used for next search.
If the key is larger than the middle element, then the right side is used for next search.
This process is continued until the key is found or the total search space is exhausted.
Algorithm:
BINARY SEARCH[A,N,KEY]
Step 1: begin
Step 2: [Initilization]
Lb=1; ub=n;
Step 3: [Search for the ITEM]
Repeat through step 4,while Lower bound is less than Upper Bound.
Step 4: [Obtain the index of middle value]
MID=(lb+ub)/2
Step 5: [Compare to search for ITEM]
If Key<A[MID] then
Ub=MID-1
Other wise if Key >A[MID] then
Lb=MID+1
Otherwise write “Match Found”
Return Middle.
Step 6: [Unsuccessful Search]
write “Match Not Found”
Step 7: Stop.
Source Code:
#include <iostream>
using namespace std;
int binarySearch(int arr[], int target, int low, int high) {
while (low <= high) {
int mid = (low + high) / 2;
if (arr[mid] == target)
return mid;
else if (arr[mid] < target)
low = mid + 1;
else
high = mid - 1; }
return -1; // Target not found}
int main() {
int n;
cout << "Enter the number of elements: ";
cin >> n;
int arr[n];
cout << "Enter the sorted elements:" << endl;
for (int i = 0; i < n; i++)
cin >> arr[i];
int target;
cout << "Enter the target element: ";
cin >> target;
int result = binarySearch(arr, target, 0, n - 1);
if (result != -1)
cout << "Target element found at index " << result << endl;
else
cout << "Target element not found in the array." << endl;
return 0;}
Input & Output :
Enter the number of elements: 5
Enter elements: 1 10 15 20 45
Target : 10
Element found at 1 index

Enter the number of elements: 4


Enter elements: 23 43 52 67
Target : 25
Element is not found in array
Remarks:Binary Search is highly efficient for sorted arrays, with a time complexity of O(log n), where n is the number of elements. Its divide-and-conquer approach makes it an invaluable tool for quick and
precise element retrieval.
14.Problem Name:Finding the Convex Hull of a Set of Points using Quick Hull
Analysis:
The Convex Hull of a set of points is the smallest convex polygon that encloses all the points. Quick Hull is an efficient algorithm to compute the convex hull of a set of points in a 2D plane. It works by
recursively finding the convex hull of the points on the left and right of the line connecting the two extreme points. Quick Hull has an average-case time complexity of O(n log n), making it efficient for large
sets of points.
Algorithm:
procedure quickHull(points)
if number of points <= 1
return points
leftmost = point with the smallest x-coordinate
rightmost = point with the largest x-coordinate
convexHull = [leftmost, rightmost]
divide points into two sets: leftSet (above leftmost-rightmost line) and rightSet (below rightmost-leftmost line)
findHull(leftSet, leftmost, rightmost)
findHull(rightSet, rightmost, leftmost)
return convexHull
end procedure
procedure findHull(points, p1, p2)
if points is empty
return
select the point with the maximum distance from the line p1-p2 as p
add p to convexHull
divide points into two sets: upperSet (above p1-p line) and lowerSet (below p1-p line)
findHull(upperSet, p1, p)
findHull(lowerSet, p, p2)
end procedure
Source code:
#include <iostream>
#include <vector>
#include <algorithm>
struct Point {
int x, y;
};
// Find the side of a point with respect to a line
int findSide(const Point& p1, const Point& p2, const Point& p) {
int val = (p.y - p1.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p.x - p1.x);
if (val > 0) return 1; // Right side
if (val < 0) return -1; // Left side
return 0; // Collinear
}
// Find the distance between two points
int findDistance(const Point& p1, const Point& p2) {
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
// Find the points that are on the convex hull
void quickHullRec(std::vector<Point>& points, const Point& p1, const Point& p2, int side,
std::vector<Point>& convexHull) {
int ind = -1;
int maxDist = 0;
// Find the point with the maximum distance from the line
for (int i = 0; i < points.size(); i++) {
int currDist = findDistance(p1, p2) - findDistance(p1, points[i]);
if (findSide(p1, p2, points[i]) == side && currDist > maxDist) {
ind = i;
maxDist = currDist;
}
}
// If no point is found, add the endpoints to the convex hull
if (ind == -1) {
convexHull.push_back(p1);
convexHull.push_back(p2);
return;
}
// Recursively apply QuickHull on both sides of the line
quickHullRec(points, points[ind], p1, -findSide(points[ind], p1, p2), convexHull);
quickHullRec(points, points[ind], p2, -findSide(points[ind], p2, p1), convexHull);
}
// Wrapper function for the QuickHull algorithm
std::vector<Point> quickHull(std::vector<Point>& points) {
if (points.size() < 3) {
std::cerr << "Convex hull not possible with less than 3 points.\n";
return {};
}
std::vector<Point> convexHull;
// Find the leftmost and rightmost points
int min_x = 0, max_x = 0;
for (int i = 1; i < points.size(); i++) {
if (points[i].x < points[min_x].x) min_x = i;
if (points[i].x > points[max_x].x) max_x = i;
}
// Recursively find the convex hull on both sides of the line
quickHullRec(points, points[min_x], points[max_x], 1, convexHull);
quickHullRec(points, points[min_x], points[max_x], -1, convexHull);
// Remove duplicates from the convex hull
std::sort(convexHull.begin(), convexHull.end(), [](const Point& p1, const Point& p2) {
return p1.x == p2.x ? p1.y < p2.y : p1.x < p2.x;
});
convexHull.erase(std::unique(convexHull.begin(), convexHull.end()), convexHull.end());
return convexHull;
}
int main() {
int n;
std::cout << "Enter the number of points: ";
std::cin >> n;
std::vector<Point> points(n);
std::cout << "Enter the points (x y):\n";
for (int i = 0; i < n; i++) {
std::cin >> points[i].x >> points[i].y;
}
std::vector<Point> convexHull = quickHull(points);
std::cout << "Convex Hull:\n";
for (const Point& p : convexHull) {
std::cout << "(" << p.x << ", " << p.y << ")\n";
}
return 0;
}
Sample Input:
5
11
25
43
51
72
Sample Output:
Convex Hull points:
(1, 1)
(5, 1)
(7, 2)
(2, 5)
Remarks:
Quick Hull is an efficient algorithm for finding the convex hull of a set of points. It's commonly used in computer graphics and computational geometry. The algorithm divides the problem into smaller
subproblems and recursively constructs the convex hull by finding extreme points. It's more efficient than brute force approaches, especially for large datasets.
15.Problem Name: Sorting an array using Bucket Sort
Analysis: Bucket sort is a sorting technique that involves dividing elements into various groups, or buckets. These buckets are formed by uniformly distributing the elements. Once the elements are divided
into buckets, they can be sorted using any other sorting algorithm. Finally, the sorted elements are gathered together in an ordered fashion..
Algorithm:
BUCKET_SORT(A)
// A is an array of size n
Create n buckets represented by B
for i ← 1 to n do
Insert A[i] into bucket B[n*A[i]]
end
for i ← 1 to n do
sort each bucket i using insertion sort
end
Concate all buckets into sorted order
Source Code:
#include <iostream>
#include <vector>
#include <algorithm>
void bucketSort(std::vector<float>& arr) {
int n = arr.size();
std::vector<std::vector<float>> buckets(n);
for (float num : arr) {
int index = n * num;
buckets[index].push_back(num);}
for (std::vector<float>& bucket : buckets) {
std::sort(bucket.begin(), bucket.end());}
int index = 0;
for (const std::vector<float>& bucket : buckets) {
for (float num : bucket) {
arr[index++] = num; } }}
int main() {
int n;
std::cout << "Enter the number of elements: ";
std::cin >> n;
std::vector<float> arr(n);
std::cout << "Enter the elements (float values between 0 and 1):\n";
for (int i = 0; i < n; i++) {
std::cin >> arr[i];}
std::cout << "Original array: ";
for (float num : arr) {
std::cout << num << " ";}
std::cout << std::endl;
bucketSort(arr);
std::cout << "Sorted array: ";
for (float num : arr) {
std::cout << num << " "; }
std::cout << std::endl;
return 0;}
Sample Input: 5
34 3.2 56 90 1
Sample Output:
Original array: 34 3.2 56 90 1
Sorted Array: 1 3.2 34 56 90
Remarks:Bucket Sort has an average time complexity of O(n + n^2/k + k), where n is the number of elements and k is the number of buckets. It can be efficient for distributing data uniformly within a
specified range. Bucket sort can also be used as an external sorting algorithm. Bucket sort can be stable, and it depends on the algorithm used to sort those elements. Bucket sort uses spacing to sort the
elements.

You might also like