## Sorting Algorithms
### 1. Bubble Sort
Bubble Sort is a simple comparison-based sorting algorithm that
repeatedly steps through the list, compares adjacent elements, and swaps
them if they are in the wrong order.
- **Best Case**: \(O(n)\)
- **Average Case**: \(O(n^2)\)
- **Worst Case**: \(O(n^2)\)
void bubbleSort(std::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]) {
std::swap(arr[j], arr[j+1]);
}
}
}
}
### 2. Selection Sort
Selection Sort divides the input list into two parts: the sublist of items
already sorted and the sublist of items remaining to be sorted. It repeatedly
selects the smallest (or largest) element from the unsorted sublist and
moves it to the sorted sublist.
- **Best Case**: \(O(n^2)\)
- **Average Case**: \(O(n^2)\)
- **Worst Case**: \(O(n^2)\)
void selectionSort(std::vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n-1; i++) {
int minIndex = i;
for (int j = i+1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
std::swap(arr[i], arr[minIndex]);
}
}
### 3. Insertion Sort
Insertion Sort builds the final sorted array one item at a time. It is much
less efficient on large lists than more advanced algorithms such as
quicksort, heapsort, or merge sort.
- **Best Case**: \(O(n)\)
- **Average Case**: \(O(n^2)\)
- **Worst Case**: \(O(n^2)\)
void insertionSort(std::vector<int>& arr) {
int n = arr.size();
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
### 4. Merge Sort
Merge Sort is an efficient, stable, comparison-based, divide and conquer
sorting algorithm. Most implementations produce a stable sort, meaning
that the implementation preserves the input order of equal elements in the
sorted output.
- **Best Case**: \(O(n \log n)\)
- **Average Case**: \(O(n \log n)\)
- **Worst Case**: \(O(n \log n)\)
void merge(std::vector<int>& arr, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
std::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];
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(std::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
Quick Sort is an efficient, comparison-based, divide and conquer sorting
algorithm. It works by selecting a 'pivot' element from the array and
partitioning the other elements into two sub-arrays according to whether
they are less than or greater than the pivot.
- **Best Case**: \(O(n \log n)\)
- **Average Case**: \(O(n \log n)\)
- **Worst Case**: \(O(n^2)\)
int partition(std::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++;
std::swap(arr[i], arr[j]);
}
}
std::swap(arr[i + 1], arr[high]);
return (i + 1);
}
void quickSort(std::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
Heap Sort is a comparison-based sorting algorithm that uses a binary heap
data structure. It is similar to selection sort where we first find the
maximum element and place it at the end.
- **Best Case**: \(O(n \log n)\)
- **Average Case**: \(O(n \log n)\)
- **Worst Case**: \(O(n \log n)\)
void heapify(std::vector<int>& arr, int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] > arr[largest]) {
largest = left;
}
if (right < n && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {
std::swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heapSort(std::vector<int>& arr) {
int n = arr.size();
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
for (int i = n - 1; i > 0; i--) {
std::swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
### 7. Counting Sort
Counting Sort is an integer sorting algorithm that assumes the range of the
numbers to be sorted is known. It counts the number of objects having
distinct key values, and using arithmetic to calculate the position of each
object.
- **Best Case**: \(O(n + k)\)
- **Average Case**: \(O(n + k)\)
- **Worst Case**: \(O(n + k)\)
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int minE = *min_element(begin(nums), end(nums));
int maxE = *max_element(begin(nums), end(nums));
unordered_map<int, int> mp;
for (int& num : nums)
mp[num]++;
int i = 0;
for (int num = minE; num <= maxE; num++) {
while (mp[num] > 0) {
nums[i] = num;
i++;
mp[num]--;
}
}
return nums;
}
};