From 1371b5390abc98ab127c5a9057cbeff6e2afbbfb Mon Sep 17 00:00:00 2001 From: David Leal Date: Thu, 1 Dec 2022 11:29:28 -0600 Subject: [PATCH] [feat/docs]: improve the `quick_sort.cpp` algorithm (#2396) * [feat/docs]: improve the `quick_sort.cpp`... ...algorithm implementation. * clang-format and clang-tidy fixes for 40c858ba * chore(fix): add original author * updating DIRECTORY.md --- DIRECTORY.md | 1 + sorting/quick_sort.cpp | 239 ++++++++++++++++++++++++++++++++--------- 2 files changed, 189 insertions(+), 51 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 5ea0f928c..c613222ef 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -17,6 +17,7 @@ * [Count Bits Flip](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/count_bits_flip.cpp) * [Count Of Set Bits](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/count_of_set_bits.cpp) * [Count Of Trailing Ciphers In Factorial N](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp) + * [Find Non Repeating Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/find_non_repeating_number.cpp) * [Hamming Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/hamming_distance.cpp) * [Set Kth Bit](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/set_kth_bit.cpp) diff --git a/sorting/quick_sort.cpp b/sorting/quick_sort.cpp index ff66b4cf2..514361444 100644 --- a/sorting/quick_sort.cpp +++ b/sorting/quick_sort.cpp @@ -1,12 +1,13 @@ /** * @file - * @brief Quick sort algorithm - * - * Implementation Details - - * Quick Sort is a divide and conquer algorithm. It picks and element as - * pivot and partition the given array around the picked pivot. There - * are many different versions of quickSort that pick pivot in different - * ways. + * @brief [Quick sort implementation](https://en.wikipedia.org/wiki/Quicksort) + * in C++ + * @details + * Quick Sort is a [divide and conquer + * algorithm](https://en.wikipedia.org/wiki/Category:Divide-and-conquer_algorithms). + * It picks an element as pivot and partition the given array around the + * picked pivot. There are many different versions of quickSort that pick pivot + * in different ways. * * 1. Always pick the first element as pivot * 2. Always pick the last element as pivot (implemented below) @@ -19,83 +20,219 @@ * than x) before x, and put all greater elements (greater than x) after * x. All this should be done in linear time * + * @author [David Leal](https://github.com/Panquesito7) + * @author [popoapp](https://github.com/popoapp) */ -#include -#include +#include /// for std::is_sorted +#include /// for std::assert +#include /// for std::time +#include /// for IO operations +#include /// for std::vector +/** + * @brief Sorting algorithms + * @namespace sorting + */ namespace sorting { /** - * This function takes last element as pivot, places - * the pivot element at its correct position in sorted - * array, and places all smaller (smaller than pivot) - * to left of pivot and all greater elements to right - * of pivot - * + * @namespace quick_sort + * @brief Functions for the [Quick sort + * implementation](https://en.wikipedia.org/wiki/Quicksort) in C++ */ - -int partition(int arr[], int low, int high) { - int pivot = arr[high]; // taking the last element as pivot - int i = (low - 1); // Index of smaller element +namespace quick_sort { +/** + * @brief Sorts the array taking the last element as pivot + * @details + * This function takes last element as pivot, places + * the pivot element at its correct position in sorted + * array, and places all smaller (smaller than pivot) + * to left of pivot and all greater elements to right of pivot + * @tparam T array type + * @param arr the array with contents given by the user + * @param low first point of the array (starting index) + * @param high last point of the array (ending index) + * @returns index of the smaller element + */ +template +int partition(std::vector *arr, const int &low, const int &high) { + T pivot = (*arr)[high]; // taking the last element as pivot + int i = (low - 1); // Index of smaller element for (int j = low; j < high; j++) { // If current element is smaller than or // equal to pivot - if (arr[j] <= pivot) { + if ((*arr)[j] <= pivot) { i++; // increment index of smaller element - int temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; + std::swap((*arr)[i], (*arr)[j]); } } - int temp = arr[i + 1]; - arr[i + 1] = arr[high]; - arr[high] = temp; + + std::swap((*arr)[i + 1], (*arr)[high]); return (i + 1); } /** - * The main function that implements QuickSort - * arr[] --> Array to be sorted, - * low --> Starting index, - * high --> Ending index + * @brief the main function that implements Quick Sort. + * + * Void function used in T (array type) function, which then + * can be used as self-tests or other functionalities. + * @tparam T array type + * @param arr array to be sorted + * @param low starting index + * @param high ending index */ -void quickSort(int arr[], int low, int high) { +template +void quick_sort(std::vector *arr, const int &low, const int &high) { if (low < high) { int p = partition(arr, low, high); - quickSort(arr, low, p - 1); - quickSort(arr, p + 1, high); + + quick_sort(arr, low, p - 1); + quick_sort(arr, p + 1, high); } } -} // namespace sorting +/** + * @brief the main function that implements Quick Sort. + * + * T (array type) function which calls the void function. Can + * be used for self-tests and other functionalities. + * @tparam T array type + * @param arr array to be sorted + * @param low starting index + * @param high ending index + */ +template +std::vector quick_sort(std::vector arr, const int &low, const int &high) { + if (low < high) { + int p = partition(&arr, low, high); -using sorting::quickSort; + quick_sort(&arr, low, p - 1); + quick_sort(&arr, p + 1, high); + } + return arr; +} -// prints the array after sorting -void show(int arr[], int size) { +/** + * @brief Utility function to print the array contents + * @param arr the array to be printed + * @param size size of the given array + * @returns void + */ +template +void show(const std::vector &arr, const int &size) { for (int i = 0; i < size; i++) std::cout << arr[i] << " "; std::cout << "\n"; } -/** Driver program to test above functions */ -int main() { - int size; - std::cout << "\nEnter the number of elements : "; +} // namespace quick_sort +} // namespace sorting - std::cin >> size; +/** + * @brief Self-test implementations + * @returns void + */ +static void tests() { + // 1st test (normal numbers) + std::vector arr = {5, 3, 8, 12, 14, 16, 28, 96, 2, 5977}; + std::vector arr_sorted = sorting::quick_sort::quick_sort( + arr, 0, int(std::end(arr) - std::begin(arr)) - 1); - int *arr = new int[size]; + assert(std::is_sorted(std::begin(arr_sorted), std::end(arr_sorted))); + std::cout << "\n1st test: passed!\n"; - std::cout << "\nEnter the unsorted elements : "; + // 2nd test (normal and negative numbers) + std::vector arr2 = {9, 15, 28, 96, 500, -4, -58, + -977, -238, -800, -21, -53, -55}; + std::vector arr_sorted2 = sorting::quick_sort::quick_sort( + arr2, 0, std::end(arr2) - std::begin(arr2)); - for (int i = 0; i < size; ++i) { - std::cout << "\n"; - std::cin >> arr[i]; + assert(std::is_sorted(std::begin(arr_sorted2), std::end(arr_sorted2))); + std::cout << "2nd test: passed!\n"; + + // 3rd test (decimal and normal numbers) + std::vector arr3 = {29, 36, 1100, 0, 77, 1, + 6.7, 8.97, 1.74, 950.10, -329.65}; + std::vector arr_sorted3 = sorting::quick_sort::quick_sort( + arr3, 0, int(std::end(arr3) - std::begin(arr3)) - 1); + + assert(std::is_sorted(std::begin(arr_sorted3), std::end(arr_sorted3))); + std::cout << "3rd test: passed!\n"; + + // 4th test (random decimal and negative numbers) + size_t size = std::rand() % 750 + 100; + + std::vector arr4(size); + for (uint64_t i = 0; i < size; i++) { + arr4[i] = static_cast(std::rand()) / + static_cast(RAND_MAX / 999.99 - 0.99) - + 250; + } + + std::vector arr4_sorted = sorting::quick_sort::quick_sort( + arr4, 0, int(std::end(arr4) - std::begin(arr4)) - 1); + assert(std::is_sorted(std::begin(arr4_sorted), std::end(arr4_sorted))); + + std::cout << "4th test: passed!\n"; + + // Printing all sorted arrays + std::cout << "\n\tPrinting all sorted arrays:\t\n"; + + std::cout << "1st array:\n"; + sorting::quick_sort::show(arr_sorted, std::end(arr) - std::begin(arr)); + std::cout << std::endl; + std::cout << "2nd array:\n"; + sorting::quick_sort::show(arr_sorted2, std::end(arr2) - std::begin(arr2)); + std::cout << std::endl; + std::cout << "3rd array:\n"; + sorting::quick_sort::show(arr_sorted3, + int(std::end(arr3) - std::begin(arr3)) - 1); + std::cout << std::endl; + std::cout << "Start: 4th array:\n\n"; + sorting::quick_sort::show( + arr4_sorted, int(std::end(arr4_sorted) - std::begin(arr4_sorted)) - 1); + std::cout << "\nEnd: 4th array.\n"; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + int choice = 0; + + std::cout << "\tAvailable modes\t\n\n"; + std::cout << "1. Self-tests mode\n2. Interactive mode"; + + std::cout << "\nChoose a mode: "; + std::cin >> choice; + std::cout << "\n"; + + while ((choice != 1) && (choice != 2)) { + std::cout << "Invalid option. Choose between the valid modes: "; + std::cin >> choice; + } + + if (choice == 1) { + std::srand(std::time(nullptr)); + tests(); // run self-test implementations + } else if (choice == 2) { + int size = 0; + std::cout << "\nEnter the number of elements: "; + + std::cin >> size; + std::vector arr(size); + + std::cout + << "\nEnter the unsorted elements (can be negative/decimal): "; + + for (int i = 0; i < size; ++i) { + std::cout << "\n"; + std::cin >> arr[i]; + } + sorting::quick_sort::quick_sort(&arr, 0, size - 1); + std::cout << "\nSorted array: \n"; + sorting::quick_sort::show(arr, size); } - quickSort(arr, 0, size); - std::cout << "Sorted array\n"; - show(arr, size); - delete[] arr; return 0; }