diff --git a/sorting/hybrid_quick_insertion_selection.cpp b/sorting/hybrid_quick_insertion_selection.cpp new file mode 100644 index 0000000000..996443787a --- /dev/null +++ b/sorting/hybrid_quick_insertion_selection.cpp @@ -0,0 +1,209 @@ +/** + * @file + * @brief Hybrid of QuickSort, InsertionSort and SelectionSort + * https://es.wikipedia.org/wiki/Quicksort + * https://en.wikipedia.org/wiki/Selection_sort + * https://en.wikipedia.org/wiki/Insertion_sort + * @details + * this is a hybrid sorting algorithm + * uses quicksort to split the array in two + * sorts the left half with insertion sort + * sorts the right half with selection sort + * created for educational purposes not optimized for speed. + * @author Cesar (https://github.com/cesar-011) + * @see quick_sort.cpp, insertion_sort.cpp, selection_sort_iterative.cpp + */ + +#include // for std::is_sorted +#include // for assert +#include // for IO +#include // for vector in test + +/** + * @brief swap two elements of an array + */ +template +void swap(T *arr, int i, int j) { + T aux = arr[i]; + arr[i] = arr[j]; + arr[j] = aux; +} + +/** + * @brief print the array + */ +template +void print_array(T *arr, int size) { + for (int i = 0; i < size; i++) { + std::cout << arr[i] << " "; + } +} + +/** + * @namespace sorting + * @brief Sorting algorithms + */ +namespace sorting { + +/** + * @namespace hybrid_quick_insert_select + * @brief Hybrid of QuickSort, InsertionSort and SelectionSort algorithms + */ +namespace hybrid_quick_insert_select { + +/** + * @brief Sorts an array using a hybrid of QuickSort, Insertion Sort, and + * Selection Sort. + * + * This algorithm partitions the array using QuickSort's partitioning scheme. + * It then applies Insertion Sort to the left half and Selection Sort to the + * right half. This hybrid is intended for educational purposes and not + * optimized for performance. + * + * @tparam T Type of the elements in the array. Must support comparison + * operators. + * @param arr Pointer to the array to be sorted. + * @param low Starting index of the subarray to sort. + * @param high Ending index of the subarray to sort (inclusive). + */ +template +void hybrid_quick_insertion_selection(T *arr, int low, int high) { + if (low >= high) + return; // Empty range + // A single iteration of Quicksort partitioning to divide the array into two + // halves + int i = low; + int f = high - 1; + T pivot = arr[(i + f) / 2]; + while (i <= f) { + while (arr[i] < pivot) i++; + while (arr[f] > pivot) f--; + if (i <= f) { + swap(arr, i, f); + i++; + f--; + } + } + + // Insertion at the left + if (low < f) { + for (int k = low + 1; k <= f; k++) { + int key = arr[k]; + int j = k - 1; + while (j >= low && arr[j] > key) { + arr[j + 1] = arr[j]; + j--; + } + arr[j + 1] = key; + } + } + + // Selection at the right + if (i < high) { + for (int k = i; k < high; k++) { + int minimum = arr[k]; + int min_ind = k; + int j = k + 1; + while (j < high) { + if (arr[j] < minimum) { + minimum = arr[j]; + min_ind = j; + } + j++; + } + swap(arr, k, min_ind); + } + } +} +} // namespace hybrid_quick_insert_select +} // namespace sorting + +static void test() { + using sorting::hybrid_quick_insert_select::hybrid_quick_insertion_selection; + + // Test 1: empty + { + std::vector arr = {}; + hybrid_quick_insertion_selection(arr.data(), 0, + static_cast(arr.size())); + assert(std::is_sorted(arr.begin(), arr.end())); + } + + // Test 2: one element + { + std::vector arr = {42}; + hybrid_quick_insertion_selection(arr.data(), 0, + static_cast(arr.size())); + assert(std::is_sorted(arr.begin(), arr.end())); + } + + // Test 3: positive numbers + { + std::vector arr = {1, 2, 3, 4, 5}; + hybrid_quick_insertion_selection(arr.data(), 0, + static_cast(arr.size())); + assert(std::is_sorted(arr.begin(), arr.end())); + } + + // Test 4: positive and negative numbers + { + std::vector arr = {-5, 4, -3, 2, 1}; + hybrid_quick_insertion_selection(arr.data(), 0, + static_cast(arr.size())); + assert(std::is_sorted(arr.begin(), arr.end())); + } + + // Test 5: repeated elements + { + std::vector arr = {3, 1, 2, 3, 2, 1, 4}; + hybrid_quick_insertion_selection(arr.data(), 0, + static_cast(arr.size())); + assert(std::is_sorted(arr.begin(), arr.end())); + } + + // Test 6: negative numbers + { + std::vector arr = {-10, -7, -8, -9, -1, -5}; + hybrid_quick_insertion_selection(arr.data(), 0, + static_cast(arr.size())); + assert(std::is_sorted(arr.begin(), arr.end())); + } + + // Test 7: big array + { + std::vector arr(1000); + for (int i = 0; i < 1000; ++i) { + arr[i] = 1000 - i; + } + hybrid_quick_insertion_selection(arr.data(), 0, + static_cast(arr.size())); + assert(std::is_sorted(arr.begin(), arr.end())); + } + + std::cout << "All tests passed successfully!\n"; +} + +/** + * @brief Main program to demonstrate the hybrid sorting algorithm. + * + * Runs the built-in self-tests, then sorts a sample array using the hybrid + * algorithm that combines QuickSort, Insertion Sort, and Selection Sort. + * + * The array is printed before and after sorting to show the result. + * + * @return int Program exit code (0 indicates successful execution). + */ +int main() { + test(); // run self-test implementations + + // An example + int N = 8; + int array[N] = {8, 5, 9, 20, 2, 13, 3, 1}; + print_array(array, N); + std::cout << '\n'; + sorting::hybrid_quick_insert_select::hybrid_quick_insertion_selection(array, + 0, N); + print_array(array, N); + std::cout << '\n'; + return 0; +}