written on 4 November 2023
Views : Loading...
Bubble sort is a 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. The pass through the list is repeated until no swaps are needed, indicating that the list is sorted.
Time Complexity: $O(N^2)$
Space Complexity: $O(1)$
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
// Last i elements are already in place, so no need to compare them
for (int j = 0; j < n - i - 1; j++) {
// Compare adjacent elements and swap them if they are in the wrong order
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
Insertion sort is a comparison-based sorting algorithm that builds the final sorted array one item at a time. It repeatedly takes an element from the unsorted part and inserts it into its correct position in the sorted part of the array.
void insertionSort(int arr[], int n) {
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
// Move elements of arr[0..i-1] that are greater than key
// to one position ahead of their current position
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
Selection sort is a comparison-based sorting algorithm that divides the input array into two parts: a sorted part and an unsorted part. The algorithm repeatedly selects the smallest (or largest, depending on the sorting order) element from the unsorted part and moves it to its correct position in the sorted part.
void selectionSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
// Find the minimum element in the unsorted part of the array
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// Swap the minimum element with the current element
if (minIndex != i) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
Quick sort is a comparison-based sorting algorithm that employs a divide-and-conquer strategy. It selects a 'pivot' element from the array and partitions the other elements into two sub-arrays, according to whether they are less than or greater than the pivot. The sub-arrays are then recursively sorted.
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // Choose the last element as the pivot
int i = (low - 1); // Index of the smaller element
for (int j = low; j < high; j++) {
// If the current element is smaller than or equal to the pivot
if (arr[j] <= pivot) {
i++;
// Swap arr[i] and arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// Swap arr[i+1] and arr[high] (pivot)
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1;
}
// Function to perform Quick Sort
void quickSort(int arr[], int low, int high) {
if (low < high) {
// Find the pivot element such that
// element smaller than pivot are on the left
// and elements greater than pivot are on the right
int pivotIndex = partition(arr, low, high);
// Recursively sort the elements before and after the pivot
quickSort(arr, low, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, high);
}
}
// Run quickSort(arr,0,n-1);
Heap sort is a comparison-based sorting algorithm that uses a binary heap data structure. A binary heap is a complete binary tree in which every parent node is less (in a max-heap) or greater (in a min-heap) than its children. The heap property ensures that the largest (in a max-heap) or smallest (in a min-heap) element is always at the root.
Best Case: $O(n log n)$ Average Case: $O(n log n)$ Worst Case: $O(n log n)$
void heapify(vector<int>& arr, int n, int i) {
int largest = i; // Initialize the largest as the root
int left = 2 * i + 1; // Left child
int right = 2 * i + 2; // Right child
// If the left child is larger than the root
if (left < n && arr[left] > arr[largest])
largest = left;
// If the right child is larger than the largest so far
if (right < n && arr[right] > arr[largest])
largest = right;
// If the largest is not the root
if (largest != i) {
swap(arr[i], arr[largest]);
// Recursively heapify the affected sub-tree
heapify(arr, n, largest);
}
}
// Main function to perform Heap Sort
void heapSort(vector<int>& arr) {
int n = arr.size();
// Build a max heap
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// Extract elements one by one from the heap
for (int i = n - 1; i >= 0; i--) {
swap(arr[0], arr[i]); // Move the current root to the end
heapify(arr, i, 0); // Call max heapify on the reduced heap
}
}
Merge sort is a comparison-based sorting algorithm that divides the input array into two halves, recursively sorts these halves, and then merges them to create a single sorted array. The key concept behind merge sort is the "divide and conquer" approach.
// Merge two sorted subarrays into a single sorted subarray
void merge(vector<int>& arr, int left, int middle, int right) {
int n1 = middle - left + 1;
int n2 = right - middle;
// Create temporary arrays to hold the data
vector<int> L(n1);
vector<int> R(n2);
// Copy data to temporary arrays L[] and R[]
for (int i = 0; i < n1; i++) {
L[i] = arr[left + i];
}
for (int j = 0; j < n2; j++) {
R[j] = arr[middle + 1 + j];
}
// Merge the two subarrays back into the original array
int i = 0; // Index for the left subarray
int j = 0; // Index for the right subarray
int k = left; // Index for the merged subarray
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// Copy the remaining elements of L[], if any
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
// Copy the remaining elements of R[], if any
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
// Main merge sort function
void mergeSort(vector<int>& arr, int left, int right) {
if (left < right) {
int middle = left + (right - left) / 2;
// Sort the first and second halves
mergeSort(arr, left, middle);
mergeSort(arr, middle + 1, right);
// Merge the sorted halves
merge(arr, left, middle, right);
}
}
Tim Sort is a hybrid sorting algorithm that combines the principles of Merge Sort and Insertion Sort. It was designed to address the challenges posed by sorting arrays of various sizes efficiently. Tim Sort gets its name from its creator, Tim Peters, who developed it for the Python programming language.
def insertion_sort(arr, left, right):
for i in range(left + 1, right + 1):
key_item = arr[i]
j = i - 1
while j >= left and arr[j] > key_item:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key_item
def merge(arr, l, m, r):
len1, len2 = m - l + 1, r - m
left, right = [], []
for i in range(0, len1):
left.append(arr[l + i])
for i in range(0, len2):
right.append(arr[m + 1 + i])
i, j, k = 0, 0, l
while i < len1 and j < len2:
if left[i] <= right[j]:
arr[k] = left[i]
i += 1
else:
arr[k] = right[j]
j += 1
k += 1
while i < len1:
arr[k] = left[i]
i += 1
k += 1
while j < len2:
arr[k] = right[j]
j += 1
k += 1
def timsort(arr):
min_run = 32
n = len(arr)
for start in range(0, n, min_run):
end = min((start + min_run - 1), (n - 1))
insertion_sort(arr, start, end)
size = min_run
while size < n:
for start in range(0, n, size * 2):
mid = min((n - 1), (start + size - 1))
end = min((n - 1), (start + size * 2 - 1))
if mid < end:
merge(arr, start, mid, end)
size *= 2
Counting sort is a non-comparative integer sorting algorithm that works by determining the count of elements with distinct key values and using this information to place each element in its correct sorted position. It's highly efficient when sorting a small range of non-negative integers.
void countingSort(vector<int>& arr) {
int max_value = *max_element(arr.begin(), arr.end()); // Find the maximum value in the input array
int min_value = *min_element(arr.begin(), arr.end()); // Find the minimum value in the input array
int range = max_value - min_value + 1; // Calculate the range of input values
// Create a frequency array to store the count of each unique element
vector<int> frequency(range, 0);
// Count the occurrences of each unique element in the input array
for (int i = 0; i < arr.size(); i++) {
frequency[arr[i] - min_value]++;
}
int index = 0; // Index for the sorted array
// Reconstruct the sorted array from the frequency array
for (int i = 0; i < range; i++) {
while (frequency[i] > 0) {
arr[index] = i + min_value;
index++;
frequency[i]--;
}
}
}
Bucket sort is a distribution-based sorting algorithm. It works by dividing the input into a finite number of "buckets" and then sorting the elements within each bucket. After that, the sorted buckets are concatenated to produce the final sorted array.
// Function to perform bucket sort
void bucketSort(vector<float>& arr) {
int n = arr.size();
// Create an array of empty buckets
vector<vector<float>> buckets(n);
// Place elements in their respective buckets
for (int i = 0; i < n; i++) {
int bucketIndex = n * arr[i];
buckets[bucketIndex].push_back(arr[i]);
}
// Sort each bucket (e.g., using insertion sort)
for (int i = 0; i < n; i++) {
sort(buckets[i].begin(), buckets[i].end());
}
// Concatenate the sorted buckets to form the final sorted array
int index = 0;
for (int i = 0; i < n; i++) {
for (float value : buckets[i]) {
arr[index] = value;
index++;
}
}
}
Radix sort is a non-comparative sorting algorithm that processes data by taking a look at the individual digits of each number in the dataset. It sorts numbers based on the values of their digits, starting from the least significant digit (LSD) to the most significant digit (MSD). The term "radix" refers to the base of the number system, typically binary (base-2), decimal (base-10), or hexadecimal (base-16).
// Function to find the maximum element in an array
int findMax(vector<int>& arr) {
int max = arr[0];
for (int i = 1; i < arr.size(); i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
// Function to perform counting sort based on a specific digit (e.g., 1s place, 10s place)
void countingSortByDigit(vector<int>& arr, int exp) {
int n = arr.size();
vector<int> output(n, 0);
vector<int> count(10, 0);
// Count the occurrences of each digit in the current place value
for (int i = 0; i < n; i++) {
count[(arr[i] / exp) % 10]++;
}
// Calculate the cumulative count of the digits
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// Build the output array by placing elements in the correct position
for (int i = n - 1; i >= 0; i--) {
output[count[(arr[i] / exp) % 10] - 1] = arr[i];
count[(arr[i] / exp) % 10]--;
}
// Copy the sorted elements back to the original array
for (int i = 0; i < n; i++) {
arr[i] = output[i];
}
}
// Radix Sort function
void radixSort(vector<int>& arr) {
int max = findMax(arr);
// Perform counting sort for each place value (1s, 10s, 100s, ...)
for (int exp = 1; max / exp > 0; exp *= 10) {
countingSortByDigit(arr, exp);
}
}
Shell sort is an in-place, non-comparative sorting algorithm that improves upon the insertion sort by allowing elements to move in gaps greater than one position at a time. It's named after its inventor, Donald Shell, who introduced the concept of diminishing increment gaps to speed up the sorting process.
// Function to perform Shell Sort
void shellSort(vector<int>& arr) {
int n = arr.size();
// Start with a large gap and reduce it in each pass
for (int gap = n / 2; gap > 0; gap /= 2) {
// Perform insertion sort for the elements at the current gap
for (int i = gap; i < n; i++) {
int temp = arr[i];
int j;
// Move elements that are greater than the current element to the right
for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
arr[j] = arr[j - gap];
}
// Place the current element in its correct position
arr[j] = temp;
}
}
}
Pancake sorting is a sorting algorithm that models the act of sorting a stack of pancakes. The algorithm sorts a disordered stack of pancakes by using a spatula to perform a sequence of flips. Each flip rearranges a portion of the stack, with the goal of achieving a fully sorted stack.
Pancake sorting is a unique algorithm, but it's not the most efficient one for large datasets. The primary interest in pancake sorting lies in its simplicity and curiosity value.
// Function to flip the first k elements of the array
void flip(vector<int>& arr, int k) {
int i = 0;
while (i < k - i) {
swap(arr[i], arr[k - i]);
i++;
}
}
// Function to find the index of the maximum element in the array
int findMaxIndex(vector<int>& arr, int n) {
int maxIndex = 0;
for (int i = 1; i < n; i++) {
if (arr[i] > arr[maxIndex]) {
maxIndex = i;
}
}
return maxIndex;
}
// Function to perform Pancake Sort
void pancakeSort(vector<int>& arr) {
int n = arr.size();
for (int size = n; size > 1; size--) {
int maxIndex = findMaxIndex(arr, size);
if (maxIndex != size - 1) {
// Flip the stack to move the maximum element to the top
flip(arr, maxIndex);
// Flip the stack to move the maximum element to its correct position
flip(arr, size - 1);
}
}
}
DNF sorting is a sorting algorithm that was designed to solve the Dutch National Flag problem. The Dutch National Flag problem is a partitioning problem in which elements are divided into three categories, typically represented by three colors: red, white, and blue. The goal is to rearrange the elements so that all the red elements come before the white elements, which in turn come before the blue elements.
// Function to perform Dutch National Flag Sorting
void dnfSort(vector<char>& arr) {
int n = arr.size();
// Initialize pivot elements (red and blue)
char red = 'R';
char blue = 'B';
int low = 0; // Index for the white category
int high = n - 1; // Index for the unprocessed region
int i = 0;
while (i <= high) {
if (arr[i] == red) {
swap(arr[i], arr[low]);
i++;
low++;
} else if (arr[i] == blue) {
swap(arr[i], arr[high]);
high--;
} else {
i++;
}
}
}