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

Assignment

This document provides an overview of various types of algorithms, particularly focusing on sorting algorithms, their characteristics, applications, and examples. It categorizes algorithms into types such as Divide and Conquer, Greedy, Dynamic Programming, and others, detailing their descriptions, examples, and use cases. Additionally, it explores specific sorting algorithms like Bubble Sort, Quick Sort, and Merge Sort, including their working principles, complexities, and C++ implementations.

Uploaded by

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

Assignment

This document provides an overview of various types of algorithms, particularly focusing on sorting algorithms, their characteristics, applications, and examples. It categorizes algorithms into types such as Divide and Conquer, Greedy, Dynamic Programming, and others, detailing their descriptions, examples, and use cases. Additionally, it explores specific sorting algorithms like Bubble Sort, Quick Sort, and Merge Sort, including their working principles, complexities, and C++ implementations.

Uploaded by

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

Assignment: Exploring Types of Algorithms

Objective:
This assignment aims to provide an overview of various types of algorithms, their characteristics,
applications, and examples. Understanding these categories will help in selecting the right algorithm for
specific problems in computational tasks.

Introduction
Algorithms are step-by-step procedures or formulas for solving problems. They are the backbone of
computer science and are implemented in various domains like data analysis, artificial intelligence,
cryptography, and optimization. Based on their functionality and application, algorithms are categorized into
several types.

Types of Algorithms
1. Divide and Conquer Algorithms
o Description: Divide the problem into smaller sub-problems, solve them independently, and
then combine the results.
o Examples: Merge Sort, Quick Sort, Binary Search.
o Applications: Efficient sorting, searching, and optimization problems.
2. Greedy Algorithms
o Description: Make the locally optimal choice at each step with the hope of finding a global
optimum.
o Examples: Kruskal's Algorithm, Prim's Algorithm, Dijkstra's Algorithm.
o Applications: Shortest path, minimum spanning tree, and resource allocation.
3. Dynamic Programming (DP) Algorithms
o Description: Solve problems by breaking them down into smaller sub-problems, solving
each once, and storing the solutions.
o Examples: Fibonacci Sequence, Knapsack Problem, Longest Common Subsequence.
o Applications: Optimization problems in robotics, finance, and bioinformatics.
4. Backtracking Algorithms
o Description: Solve problems incrementally by trying partial solutions and then removing
solutions that fail to satisfy constraints.
o Examples: N-Queens Problem, Sudoku Solver, Hamiltonian Path.
o Applications: Constraint satisfaction problems, puzzle solving.
5. Brute Force Algorithms
o Description: Explore all possible solutions to find the answer, often inefficient but
guarantees a solution.
o Examples: Exhaustive search in combinatorial problems.
o Applications: Small-scale problems, password cracking.
6. Randomized Algorithms
o Description: Use random numbers to make decisions during execution to solve problems.
o Examples: Quick Sort

Assignment: Sorting Algorithms


Objective:
This assignment explores sorting algorithms, their types, working principles, complexities, and use cases.
Sorting is a fundamental operation in computer science that organizes data into a specific order, such as
ascending or descending.

Introduction
Sorting algorithms are essential in data organization, searching, and optimization tasks. They are broadly
categorized based on their approach, complexity, and application.

Types of Sorting Algorithms


1. Bubble Sort
 Description: Compares adjacent elements and swaps them if they are in the wrong order.
 Working Principle:
o Iterate through the list multiple times.
o Push the largest unsorted element to the end in each iteration.
 Time Complexity:
o Best case: O(n)O(n) (when the list is already sorted).
o Worst case: O(n2)O(n^2).
 Space Complexity: O(1)O(1).
 Use Case: Simple and suitable for small datasets.

2. Selection Sort
 Description: Repeatedly selects the smallest (or largest) element from the unsorted portion and places it at
the correct position.
 Working Principle:
o Find the smallest element in the unsorted part.
o Swap it with the first element of the unsorted part.
o Repeat for the remaining list.
 Time Complexity: O(n2)O(n^2) (best, average, and worst cases).
 Space Complexity: O(1)O(1).
 Use Case: Used in scenarios where memory is a constraint.

3. Insertion Sort
 Description: Builds the sorted array one element at a time by repeatedly inserting the next unsorted
element at its correct position.
 Working Principle:
o Pick an element from the unsorted part.
o Place it in the correct position in the sorted part.
 Time Complexity:
o Best case: O(n)O(n) (nearly sorted input).
o Worst case: O(n2)O(n^2).
 Space Complexity: O(1)O(1).
 Use Case: Efficient for small or nearly sorted datasets.

4. Merge Sort
 Description: Uses the divide and conquer approach to split the array into halves, sort them, and then merge
the sorted halves.
 Working Principle:
o Divide the array into two halves recursively.
o Merge the sorted halves.
 Time Complexity: O(nlog⁡n)O(n \log n) (all cases).
 Space Complexity: O(n)O(n).
 Use Case: Suitable for large datasets and linked lists.

5. Quick Sort
 Description: Uses the divide and conquer approach by selecting a pivot, partitioning the array around the
pivot, and sorting the partitions.
 Working Principle:
o Choose a pivot element.
o Rearrange elements such that smaller elements are before and larger elements are after the pivot.
o Recursively sort the partitions.
 Time Complexity:
o Best and Average case: O(nlog⁡n)O(n \log n).
o Worst case: O(n2)O(n^2) (when the pivot is poorly chosen).
 Space Complexity: O(log⁡n)O(\log n) (in-place).
 Use Case: Versatile and commonly used for general-purpose sorting.
6. Heap Sort
 Description: Builds a max heap (or min heap) from the array, then repeatedly extracts the largest (or
smallest) element and places it at the end.
 Working Principle:
o Construct a heap.
o Extract the root (largest or smallest) and rebuild the heap.
 Time Complexity: O(nlog⁡n)O(n \log n).
 Space Complexity: O(1)O(1).
 Use Case: Efficient for sorting large datasets with limited space.

7. Counting Sort
 Description: Sorts integers by counting occurrences of each element and placing them in sorted order.
 Working Principle:
o Count the frequency of each element.
o Use the count to determine the position of each element.
 Time Complexity: O(n+k)O(n + k), where kk is the range of input values.
 Space Complexity: O(n+k)O(n + k).
 Use Case: Suitable for integers or categorical data with a small range.

8. Radix Sort
 Description: Sorts numbers by processing individual digits from the least significant to the most significant
using a stable sorting algorithm like Counting Sort.
 Working Principle:
o Sort the numbers based on each digit, starting from the least significant digit.
o Repeat for all digits.
 Time Complexity: O(d×(n+k))O(d \times (n + k)), where dd is the number of digits.
 Space Complexity: O(n+k)O(n + k).
 Use Case: Sorting large datasets of integers or strings.

9. Bucket Sort
 Description: Divides elements into buckets, sorts each bucket, and concatenates them.
 Working Principle:
o Distribute elements into buckets.
o Sort each bucket individually.
o Merge the sorted buckets.
 Time Complexity: O(n+k)O(n + k) (average case).
 Space Complexity: O(n+k)O(n + k).
 Use Case: Efficient for uniformly distributed data.

Conclusion
Sorting algorithms vary in complexity, space usage, and efficiency. Choosing the right sorting algorithm
depends on the dataset size, type, and constraints like memory usage and performance requirements.
Understanding these algorithms is crucial for efficient data handling in various real-world applications.

1. Bubble Sort
Example: Input: [5, 3, 8, 6, 2]
Steps:
1. Compare the first two elements. Swap if the first is greater: [3, 5, 8, 6, 2].
2. Continue to the end of the list, moving larger elements to the right: [3, 5, 6, 2, 8].
3. Repeat until the list is fully sorted: [2, 3, 5, 6, 8].
Use Case: Simple but inefficient for large datasets.

2. Selection Sort
Example: Input: [7, 2, 4, 1, 5]
Steps:
1. Find the smallest element and swap it with the first: [1, 2, 4, 7, 5].
2. Move to the next position, find the smallest in the unsorted portion, and repeat: [1, 2, 4, 5, 7].
Use Case: Efficient in memory-limited environments.

3. Insertion Sort
Example: Input: [6, 4, 3, 8, 5]
Steps:
1. Start with the second element and insert it into the correct position: [4, 6, 3, 8, 5].
2. Continue inserting the next unsorted element into the sorted section: [3, 4, 6, 8, 5].
3. Repeat until sorted: [3, 4, 5, 6, 8].
Use Case: Best for small or nearly sorted datasets.

4. Merge Sort
Example: Input: [9, 3, 7, 6, 2]
Steps:
1. Divide the array into halves: [9, 3] and [7, 6, 2].
2. Sort each half: [3, 9] and [2, 6, 7].
3. Merge the sorted halves: [2, 3, 6, 7, 9].
Use Case: Efficient for large datasets.

5. Quick Sort
Example: Input: [5, 3, 7, 6, 2]
Steps:
1. Choose a pivot (e.g., 5) and partition the array into smaller ([3, 2]) and larger ([7, 6]) sub-arrays.
2. Recursively sort the sub-arrays: [2, 3] and [6, 7].
3. Combine the results: [2, 3, 5, 6, 7].
Use Case: Versatile and commonly used for general sorting tasks.

6. Heap Sort
Example: Input: [4, 10, 3, 5, 1]
Steps:
1. Build a max heap: [10, 5, 3, 4, 1].
2. Swap the root (largest) with the last element and rebuild the heap: [5, 4, 3, 1, 10].
3. Repeat until sorted: [1, 3, 4, 5, 10].
Use Case: Suitable for large datasets with limited memory.

7. Counting Sort
Example: Input: [4, 2, 2, 8, 3]
Steps:
1. Count occurrences of each number: [0, 0, 2, 1, 1, 0, 0, 0, 1] (counts from 0 to 8).
2. Compute cumulative counts.
3. Place each element in its correct position in the output array.
Output: [2, 2, 3, 4, 8].
Use Case: Efficient for integers in a small range.

8. Radix Sort
Example: Input: [170, 45, 75, 90, 802]
Steps:
1. Sort based on the least significant digit: [170, 90, 802, 45, 75].
2. Sort based on the next significant digit: [802, 45, 75, 170, 90].
3. Repeat until sorted: [45, 75, 90, 170, 802].
Use Case: Handles large numbers efficiently.
9. Bucket Sort
Example: Input: [0.42, 0.32, 0.23, 0.52, 0.73]
Steps:
1. Distribute the elements into buckets:
o [0.23, 0.32] (Bucket 1), [0.42] (Bucket 2), [0.52, 0.73] (Bucket 3).
2. Sort each bucket individually.
3. Merge the buckets: [0.23, 0.32, 0.42, 0.52, 0.73].
Use Case: Efficient for uniformly distributed data.
These examples illustrate the diversity of sorting algorithms, each suitable for specific types of datasets and
constraints.

Here are the C++ implementations of the sorting algorithms from the previous examples:

1. Bubble Sort
#include <iostream>
#include <vector>
using namespace std;

void bubbleSort(vector<int>& arr) {


int n = arr.size();
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]);
}
}
}
}

2. Selection Sort
void selectionSort(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;
}
}
swap(arr[i], arr[minIndex]);
}
}

3. Insertion Sort
void insertionSort(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;
}
}

4. Merge Sort
void merge(vector<int>& arr, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
vector<int> L(n1), R(n2);

for (int i = 0; i < n1; i++) L[i] = arr[left + i];


for (int i = 0; i < n2; i++) R[i] = arr[mid + 1 + i];

int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k++] = L[i++];
else arr[k++] = R[j++];
}

while (i < n1) arr[k++] = L[i++];


while (j < n2) arr[k++] = R[j++];
}

void mergeSort(vector<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);
}
}

5. Quick Sort
int partition(vector<int>& arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;

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


if (arr[j] < pivot) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return i + 1;
}

void quickSort(vector<int>& arr, int low, int high) {


if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}

6. Heap Sort
void heapify(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) {
swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}

void heapSort(vector<int>& arr) {


int n = arr.size();

for (int i = n / 2 - 1; i >= 0; i--) heapify(arr, n, i);


for (int i = n - 1; i > 0; i--) {
swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}

7. Counting Sort
void countingSort(vector<int>& arr) {
int maxVal = *max_element(arr.begin(), arr.end());
vector<int> count(maxVal + 1, 0);

for (int num : arr) count[num]++;


int index = 0;

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


while (count[i]--) arr[index++] = i;
}
}

8. Radix Sort
void countingSortRadix(vector<int>& arr, int exp) {
int n = arr.size();
vector<int> output(n), count(10, 0);

for (int num : arr) count[(num / exp) % 10]++;


for (int i = 1; i < 10; i++) count[i] += count[i - 1];
for (int i = n - 1; i >= 0; i--) {
int index = (arr[i] / exp) % 10;
output[--count[index]] = arr[i];
}

for (int i = 0; i < n; i++) arr[i] = output[i];


}

void radixSort(vector<int>& arr) {


int maxVal = *max_element(arr.begin(), arr.end());
for (int exp = 1; maxVal / exp > 0; exp *= 10) countingSortRadix(arr, exp);
}

9. Bucket Sort
void bucketSort(vector<float>& arr) {
int n = arr.size();
vector<vector<float>> buckets(n);

for (float num : arr) {


int index = n * num;
buckets[index].push_back(num);
}

for (int i = 0; i < n; i++) sort(buckets[i].begin(), buckets[i].end());

int index = 0;
for (auto& bucket : buckets) {
for (float num : bucket) {
arr[index++] = num;
}
}
}
These implementations closely follow the logic of the algorithms discussed earlier. Each is written for
simplicity and clarity.

Here's how the data [6, 8, 9, 10, 2, 16, 19, 4] will be sorted using each of the discussed sorting
algorithms. Below are the results after applying each algorithm:

1. Bubble Sort
Steps:
1. Compare and swap adjacent elements.
2. Repeat for n−1n-1 passes.
Result: 2,4,6,8,9,10,16,192, 4, 6, 8, 9, 10, 16, 19

2. Selection Sort
Steps:
1. Find the smallest element in the unsorted portion.
2. Place it at the beginning.
Result: 2,4,6,8,9,10,16,192, 4, 6, 8, 9, 10, 16, 19

3. Insertion Sort
Steps:
1. Take one element at a time and insert it into its correct position in the sorted portion.
Result: 2,4,6,8,9,10,16,192, 4, 6, 8, 9, 10, 16, 19

4. Merge Sort
Steps:
1. Recursively divide the array.
2. Merge sorted halves.
Result: 2,4,6,8,9,10,16,192, 4, 6, 8, 9, 10, 16, 19

5. Quick Sort
Steps:
1. Choose a pivot.
2. Partition the array and recursively sort subarrays.
Result: 2,4,6,8,9,10,16,192, 4, 6, 8, 9, 10, 16, 19

6. Heap Sort
Steps:
1. Build a max heap.
2. Swap the root with the last element and rebuild the heap.
Result: 2,4,6,8,9,10,16,192, 4, 6, 8, 9, 10, 16, 19

7. Counting Sort
Steps:
1. Count occurrences of each element.
2. Reconstruct the sorted array.
Result: 2,4,6,8,9,10,16,192, 4, 6, 8, 9, 10, 16, 19

8. Radix Sort
Steps:
1. Sort by each digit (units, tens, hundreds, etc.).
2. Reconstruct the array.
Result: 2,4,6,8,9,10,16,192, 4, 6, 8, 9, 10, 16, 19

9. Bucket Sort
Assuming input as floating-point numbers scaled appropriately:
Steps:
1. Place numbers into buckets.
2. Sort each bucket and concatenate.
Result: 2,4,6,8,9,10,16,192, 4, 6, 8, 9, 10, 16, 19

Each algorithm ultimately produces the same result, as sorting is deterministic. However, the process and
efficiency vary across these methods. Let me know if you'd like a detailed trace for a specific algorithm!

You might also like