-
-
Notifications
You must be signed in to change notification settings - Fork 7.5k
feat: add hybrid quick-insertion-selection sorting algorithm with tests #2956
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -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 <algorithm> // for std::is_sorted | ||||||||||||||||||||||
#include <cassert> // for assert | ||||||||||||||||||||||
#include <iostream> // for IO | ||||||||||||||||||||||
#include <vector> // for vector in test | ||||||||||||||||||||||
Comment on lines
+17
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
|
||||||||||||||||||||||
/** | ||||||||||||||||||||||
* @brief swap two elements of an array | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
Comment on lines
+22
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
template <typename T> | ||||||||||||||||||||||
void swap(T *arr, int i, int j) { | ||||||||||||||||||||||
T aux = arr[i]; | ||||||||||||||||||||||
arr[i] = arr[j]; | ||||||||||||||||||||||
arr[j] = aux; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
/** | ||||||||||||||||||||||
* @brief print the array | ||||||||||||||||||||||
*/ | ||||||||||||||||||||||
Comment on lines
+32
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
template <typename T> | ||||||||||||||||||||||
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 <typename T> | ||||||||||||||||||||||
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<int> arr = {}; | ||||||||||||||||||||||
hybrid_quick_insertion_selection(arr.data(), 0, | ||||||||||||||||||||||
static_cast<int>(arr.size())); | ||||||||||||||||||||||
assert(std::is_sorted(arr.begin(), arr.end())); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Test 2: one element | ||||||||||||||||||||||
{ | ||||||||||||||||||||||
std::vector<int> arr = {42}; | ||||||||||||||||||||||
hybrid_quick_insertion_selection(arr.data(), 0, | ||||||||||||||||||||||
static_cast<int>(arr.size())); | ||||||||||||||||||||||
assert(std::is_sorted(arr.begin(), arr.end())); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Test 3: positive numbers | ||||||||||||||||||||||
{ | ||||||||||||||||||||||
std::vector<int> arr = {1, 2, 3, 4, 5}; | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for all your tests you use vectors and pass the data, You could've instead designed the functions to work with vectors directly instead |
||||||||||||||||||||||
hybrid_quick_insertion_selection(arr.data(), 0, | ||||||||||||||||||||||
static_cast<int>(arr.size())); | ||||||||||||||||||||||
assert(std::is_sorted(arr.begin(), arr.end())); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Test 4: positive and negative numbers | ||||||||||||||||||||||
{ | ||||||||||||||||||||||
std::vector<int> arr = {-5, 4, -3, 2, 1}; | ||||||||||||||||||||||
hybrid_quick_insertion_selection(arr.data(), 0, | ||||||||||||||||||||||
static_cast<int>(arr.size())); | ||||||||||||||||||||||
assert(std::is_sorted(arr.begin(), arr.end())); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Test 5: repeated elements | ||||||||||||||||||||||
{ | ||||||||||||||||||||||
std::vector<int> arr = {3, 1, 2, 3, 2, 1, 4}; | ||||||||||||||||||||||
hybrid_quick_insertion_selection(arr.data(), 0, | ||||||||||||||||||||||
static_cast<int>(arr.size())); | ||||||||||||||||||||||
assert(std::is_sorted(arr.begin(), arr.end())); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Test 6: negative numbers | ||||||||||||||||||||||
{ | ||||||||||||||||||||||
std::vector<int> arr = {-10, -7, -8, -9, -1, -5}; | ||||||||||||||||||||||
hybrid_quick_insertion_selection(arr.data(), 0, | ||||||||||||||||||||||
static_cast<int>(arr.size())); | ||||||||||||||||||||||
assert(std::is_sorted(arr.begin(), arr.end())); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
// Test 7: big array | ||||||||||||||||||||||
{ | ||||||||||||||||||||||
std::vector<int> arr(1000); | ||||||||||||||||||||||
for (int i = 0; i < 1000; ++i) { | ||||||||||||||||||||||
arr[i] = 1000 - i; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
hybrid_quick_insertion_selection(arr.data(), 0, | ||||||||||||||||||||||
static_cast<int>(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'; | ||||||||||||||||||||||
Comment on lines
+198
to
+207
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
return 0; | ||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.