Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 18

1.

Problem Name: Sorting an Array using Selection Sort


Analysis: Selection Sort is a simple sorting algorithm that repeatedly selects the smallest element from the unsorted portion of
the array and places it at the beginning. Although it's easy to understand and implement, its time complexity of O(n^2) makes it
inefficient for large datasets.
Algorithm (Pseudo Code):
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 forend 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 :8
Original array: 22 150 240 13 622 4 23 52
Sorted array: 4 13 22 23 52 150 240 622
Remarks: Selection Sort is a straightforward algorithm that works by repeatedly selecting the smallest element and placing it in
its correct position. While it's not suitable for large datasets due to its quadratic time complexity, it's a good example for
educational purposes and for understanding basic sorting concepts. For practical sorting tasks, more efficient algorithms like
Merge Sort, Quick Sort, or built-in sorting functions should be preferred.
2.Problem Name: Sorting an Array using Insertion Sort
Analysis: Insertion Sort is a simple sorting algorithm that builds the final sorted array one element at a time. It works by
considering one element at a time and inserting it into its correct position within the already sorted part of the array. While not
the most efficient sorting algorithm for large datasets, its simplicity and effectiveness for small datasets make it a valuable
learning tool.
Algorithm (Pseudo Code):
procedure insertionSort(A : list of sortable items)
n = length(A)
for i = 1 to n - 1
current = A[i]
j=i-1
while j >= 0 and A[j] > current
A[j + 1] = A[j]
j=j-1
end while
A[j + 1] = current
end for
end procedure
Source Code (C++):
#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 :12
Original array: 35 32 33 26 28 22 21 16 14 56 25 2
Sorted array: 2 14 16 21 22 25 26 28 32 33 35 56
Remarks: Insertion Sort is a simple yet effective algorithm for sorting an array by repeatedly inserting elements into their
correct positions within the already sorted part of the array. It's particularly efficient for small datasets and is often used in
more advanced sorting algorithms. However, for larger datasets, algorithms with better time complexity, like Merge Sort or
Quick Sort, are more suitable. Insertion Sort's adaptive nature and stability make it a valuable sorting technique.
3.Problem Name:Sorting an Array using Bubble Sort
Analysis:
Bubble Sort is a simple sorting algorithm that repeatedly steps through the list, compares adjacent elements, and swaps them if
they are in the wrong order. This process is repeated for each element in the array until the entire array is sorted. Although
Bubble Sort is not the most efficient sorting algorithm, it serves as a good example for understanding sorting techniques and
their basic principles.
Algorithm (Pseudo Code):
procedure bubbleSort(A : list of sortable items)
n = length(A)
for i = 0 to n - 1
for j = 0 to n - i - 1
if A[j] > A[j + 1]
swap A[j] and A[j + 1]
end if
end for
end for
end procedure
```

Source Code (C++):


#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 :8
Original array: 15 36 22 64 32 12 11 24
Sorted array: 11 12 15 22 24 32 36 64
Remarks:
Bubble Sort is a fundamental sorting algorithm that works by repeatedly swapping adjacent elements if they are in the wrong
order. While it's not efficient for larger datasets, it's easy to understand and serves as a basis for understanding other sorting
algorithms. It's mainly used for educational purposes or for sorting small datasets where efficiency is not a critical concern.
4.Problem Name: Sorting an Array using Quick Sort
Analysis:
Quick Sort is an efficient and widely used sorting algorithm based on 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 (Pseudo Code):
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 (C++):
#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 :8
Original array: 12 34 62 54 12 33 85 10
Sorted array: 10 12 12 33 34 54 62 85
Remarks:
Quick Sort is an efficient sorting algorithm that operates by partitioning an array and recursively sorting its sub-arrays. It's
widely used due to its speed and efficiency. However, its performance heavily depends on the choice of pivot, which can lead to
worst-case scenarios if not chosen carefully. Quick Sort is used in various libraries and programming languages for sorting large
datasets.
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 manner, i.e., it
visits all the vertices at the same level before moving to the next level. BFS is typically used to find the shortest path between
two nodes in an unweighted graph. It uses a queue data structure to maintain the order of exploration.

Algorithm:
procedure BFS(graph, start)
create an empty queue Q
enqueue start into Q
mark start as visited
while Q is not empty
current = dequeue from Q
process current
for each neighbor of current
if neighbor is not visited
mark neighbor as visited
enqueue neighbor into Q
end 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. It's used for finding the shortest path in an unweighted graph
and exploring nodes level by level. BFS is commonly employed in applications like social network analysis, shortest path
algorithms, and solving puzzles. While BFS is efficient, it may not be suitable for very large graphs due to its memory
requirements.
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 search algorithm that iterates through an array to find a target element. It works by sequentially
checking each element in the array until a match is found or the entire array is traversed. While simple, Linear Search has a
time complexity of O(n), where n is the number of elements in the array.
Algorithm:
procedure linearSearch(arr, target)
for i = 0 to length(arr) - 1
if arr[i] equals target
return i
return -1
end procedure
Source Code :
#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 :7
Original array: 12 45 7 23 56 31 78
enter target element:23
Element 23 found at index 4
Remarks:
Linear Search is a basic but inefficient search algorithm for larger datasets. It's suitable when the array is small or unsorted. It's
important to note that Linear Search compares each element sequentially, which makes it slower for larger arrays. More
advanced search algorithms like Binary Search (for sorted arrays) or hash-based techniques are usually preferred for larger and
sorted datasets.
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: Write a C++ program and algorithm for 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