chore: import upstream snapshot with attribution
Awesome CI Workflow / Code Formatter (push) Waiting to run
Awesome CI Workflow / Compile checks (macOS-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (windows-latest) (push) Blocked by required conditions
Awesome CI Workflow / Code Formatter (push) Waiting to run
Awesome CI Workflow / Compile checks (macOS-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (windows-latest) (push) Blocked by required conditions
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
# with full pathname. RELATIVE may makes it easier to extract an executable name
|
||||
# automatically.
|
||||
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
|
||||
# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
|
||||
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
# I used a simple string replace, to cut off .cpp.
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} )
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
CXX_STANDARD 14)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/sorting")
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
@@ -0,0 +1,56 @@
|
||||
// C++ program to implement gravity/bead sort
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#define BEAD(i, j) beads[i * max + j]
|
||||
|
||||
// function to perform the above algorithm
|
||||
void beadSort(int *a, int len) {
|
||||
// Find the maximum element
|
||||
int max = a[0];
|
||||
for (int i = 1; i < len; i++)
|
||||
if (a[i] > max)
|
||||
max = a[i];
|
||||
|
||||
// allocating memory
|
||||
unsigned char *beads = new unsigned char[max * len];
|
||||
memset(beads, 0, static_cast<size_t>(max) * len);
|
||||
|
||||
// mark the beads
|
||||
for (int i = 0; i < len; i++)
|
||||
for (int j = 0; j < a[i]; j++) BEAD(i, j) = 1;
|
||||
|
||||
for (int j = 0; j < max; j++) {
|
||||
// count how many beads are on each post
|
||||
int sum = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sum += BEAD(i, j);
|
||||
BEAD(i, j) = 0;
|
||||
}
|
||||
|
||||
// Move beads down
|
||||
for (int i = len - sum; i < len; i++) BEAD(i, j) = 1;
|
||||
}
|
||||
|
||||
// Put sorted values in array using beads
|
||||
for (int i = 0; i < len; i++) {
|
||||
int j;
|
||||
for (j = 0; j < max && BEAD(i, j); j++) {
|
||||
}
|
||||
|
||||
a[i] = j;
|
||||
}
|
||||
delete[] beads;
|
||||
}
|
||||
|
||||
// driver function to test the algorithm
|
||||
int main() {
|
||||
int a[] = {5, 3, 1, 7, 4, 1, 1, 20};
|
||||
int len = sizeof(a) / sizeof(a[0]);
|
||||
|
||||
beadSort(a, len);
|
||||
|
||||
for (int i = 0; i < len; i++) printf("%d ", a[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief [Binary Insertion Sort Algorithm
|
||||
* (Insertion Sort)](https://en.wikipedia.org/wiki/Insertion_sort)
|
||||
*
|
||||
* \details
|
||||
* If the cost of comparisons exceeds the cost of swaps, as is the case for
|
||||
* example with string keys stored by reference or with human interaction (such
|
||||
* as choosing one of a pair displayed side-by-side), then using binary
|
||||
* insertion sort may yield better performance. Binary insertion sort employs a
|
||||
* binary search to determine the correct location to insert new elements, and
|
||||
* therefore performs ⌈log2 n⌉ comparisons in the worst case. When each element
|
||||
* in the array is searched for and inserted this is O(n log n). The algorithm
|
||||
* as a whole still has a running time of O(n2) on average because of the series
|
||||
* * of swaps required for each insertion. However it has several advantages
|
||||
* such as
|
||||
* 1. Easy to implement
|
||||
* 2. For small set of data it is quite efficient
|
||||
* 3. More efficient that other Quadratic complexity algorithms like
|
||||
* Selection sort or bubble sort.
|
||||
* 4. It is efficient to use it when the cost of comparison is high.
|
||||
* 5. It's stable that is it does not change the relative order of
|
||||
* elements with equal keys.
|
||||
* 6. It can sort the array or list as it receives.
|
||||
*
|
||||
* Example execution steps:
|
||||
* 1. Suppose initially we have
|
||||
* \f{bmatrix}{40 &30 &20 &50 &10\f}
|
||||
* 2. We start traversing from 40 till we reach 10
|
||||
* when we reach at 30 we find that it is not at it's correct place so we take
|
||||
* 30 and place it at a correct position thus the array will become
|
||||
* \f{bmatrix}{30 &40 &20 &50 &10\f}
|
||||
* 3. In the next iteration we are at 20 we find that this is also misplaced so
|
||||
* we place it at the correct sorted position thus the array in this iteration
|
||||
* becomes
|
||||
* \f{bmatrix}{20 &30 &40 &50 &10\f}
|
||||
* 4. We do not do anything with 50 and move on to the next iteration and
|
||||
* select 10 which is misplaced and place it at correct position. Thus, we have
|
||||
* \f{bmatrix}{10 &20 &30 &40 &50\f}
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for algorithm functions
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for working with vectors
|
||||
|
||||
/**
|
||||
* \namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
|
||||
/**
|
||||
* \brief Binary search function to find the most suitable pace for an element.
|
||||
* \tparam T The generic data type.
|
||||
* \param arr The actual vector in which we are searching a suitable place for
|
||||
* the element. \param val The value for which suitable place is to be found.
|
||||
* \param low The lower bound of the range we are searching in.
|
||||
* \param high The upper bound of the range we are searching in.
|
||||
* \returns the index of most suitable position of val.
|
||||
*/
|
||||
template <class T>
|
||||
int64_t binary_search(std::vector<T> &arr, T val, int64_t low, int64_t high) {
|
||||
if (high <= low) {
|
||||
return (val > arr[low]) ? (low + 1) : low;
|
||||
}
|
||||
int64_t mid = low + (high - low) / 2;
|
||||
if (arr[mid] > val) {
|
||||
return binary_search(arr, val, low, mid - 1);
|
||||
} else if (arr[mid] < val) {
|
||||
return binary_search(arr, val, mid + 1, high);
|
||||
} else {
|
||||
return mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Insertion sort function to sort the vector.
|
||||
* \tparam T The generic data type.
|
||||
* \param arr The actual vector to sort.
|
||||
* \returns Void.
|
||||
*/
|
||||
template <typename T>
|
||||
void insertionSort_binsrch(std::vector<T> &arr) {
|
||||
int64_t n = arr.size();
|
||||
|
||||
for (int64_t i = 1; i < n; i++) {
|
||||
T key = arr[i];
|
||||
int64_t j = i - 1;
|
||||
int64_t loc = sorting::binary_search(arr, key, 0, j);
|
||||
while (j >= loc) {
|
||||
arr[j + 1] = arr[j];
|
||||
j--;
|
||||
}
|
||||
arr[j + 1] = key;
|
||||
}
|
||||
}
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
/* descriptions of the following test */
|
||||
/* 1st test:
|
||||
[5, -3, -1, -2, 7] returns [-3, -2, -1, 5, 7] */
|
||||
std::vector<int64_t> arr1({5, -3, -1, -2, 7});
|
||||
std::cout << "1st test... ";
|
||||
sorting::insertionSort_binsrch(arr1);
|
||||
assert(std::is_sorted(std::begin(arr1), std::end(arr1)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
/* 2nd test:
|
||||
[12, 26, 15, 91, 32, 54, 41] returns [12, 15, 26, 32, 41, 54, 91] */
|
||||
std::vector<int64_t> arr2({12, 26, 15, 91, 32, 54, 41});
|
||||
std::cout << "2nd test... ";
|
||||
sorting::insertionSort_binsrch(arr2);
|
||||
assert(std::is_sorted(std::begin(arr2), std::end(arr2)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
/* 3rd test:
|
||||
[7.1, -2.5, -4.0, -2.1, 5.7] returns [-4.0, -2.5, -2.1, 5.7, 7.1] */
|
||||
std::vector<float> arr3({7.1, -2.5, -4.0, -2.1, 5.7});
|
||||
std::cout << "3rd test... ";
|
||||
sorting::insertionSort_binsrch(arr3);
|
||||
assert(std::is_sorted(std::begin(arr3), std::end(arr3)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
/* 4th test:
|
||||
[12.8, -3.7, -20.7, -7.1, 2.2] returns [-20.7, -7.1, -3.7, 2.2, 12.8] */
|
||||
std::vector<float> arr4({12.8, -3.7, -20.7, -7.1, 2.2});
|
||||
std::cout << "4th test... ";
|
||||
sorting::insertionSort_binsrch(arr4);
|
||||
assert(std::is_sorted(std::begin(arr4), std::end(arr4)));
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @return 0 on exit.
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Source : https://www.geeksforgeeks.org/bitonic-sort/
|
||||
|
||||
/* C++ Program for Bitonic Sort. Note that this program
|
||||
works only when size of input is a power of 2. */
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
/*The parameter dir indicates the sorting direction, ASCENDING
|
||||
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
|
||||
then a[i] and a[j] are interchanged.*/
|
||||
void compAndSwap(int a[], int i, int j, int dir) {
|
||||
if (dir == (a[i] > a[j]))
|
||||
std::swap(a[i], a[j]);
|
||||
}
|
||||
|
||||
/*It recursively sorts a bitonic sequence in ascending order,
|
||||
if dir = 1, and in descending order otherwise (means dir=0).
|
||||
The sequence to be sorted starts at index position low,
|
||||
the parameter cnt is the number of elements to be sorted.*/
|
||||
void bitonicMerge(int a[], int low, int cnt, int dir) {
|
||||
if (cnt > 1) {
|
||||
int k = cnt / 2;
|
||||
for (int i = low; i < low + k; i++) compAndSwap(a, i, i + k, dir);
|
||||
bitonicMerge(a, low, k, dir);
|
||||
bitonicMerge(a, low + k, k, dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function first produces a bitonic sequence by recursively
|
||||
sorting its two halves in opposite sorting orders, and then
|
||||
calls bitonicMerge to make them in the same order */
|
||||
void bitonicSort(int a[], int low, int cnt, int dir) {
|
||||
if (cnt > 1) {
|
||||
int k = cnt / 2;
|
||||
|
||||
// sort in ascending order since dir here is 1
|
||||
bitonicSort(a, low, k, 1);
|
||||
|
||||
// sort in descending order since dir here is 0
|
||||
bitonicSort(a, low + k, k, 0);
|
||||
|
||||
// Will merge wole sequence in ascending order
|
||||
// since dir=1.
|
||||
bitonicMerge(a, low, cnt, dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* Caller of bitonicSort for sorting the entire array of
|
||||
length N in ASCENDING order */
|
||||
void sort(int a[], int N, int up) { bitonicSort(a, 0, N, up); }
|
||||
|
||||
// Driver code
|
||||
int main() {
|
||||
int a[] = {3, 7, 4, 8, 6, 2, 1, 5};
|
||||
int N = sizeof(a) / sizeof(a[0]);
|
||||
|
||||
int up = 1; // means sort in ascending order
|
||||
sort(a, N, up);
|
||||
|
||||
std::cout << "Sorted array: \n";
|
||||
for (int i = 0; i < N; i++) std::cout << a[i] << " ";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Bogosort algorithm](https://en.wikipedia.org/wiki/Bogosort)
|
||||
*
|
||||
* @details
|
||||
* In computer science, bogosort (also known as permutation sort, stupid sort, slowsort,
|
||||
* shotgun sort, random sort, monkey sort, bobosort or shuffle sort) is a highly inefficient
|
||||
* sorting algorithm based on the generate and test paradigm. Two versions of this algorithm
|
||||
* exist: a deterministic version that enumerates all permutations until it hits a sorted one,
|
||||
* and a randomized version that randomly permutes its input.Randomized version is implemented here.
|
||||
*
|
||||
* ### Algorithm
|
||||
* Shuffle the array untill array is sorted.
|
||||
*
|
||||
* @author [Deep Raval](https://github.com/imdeep2905)
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <random>
|
||||
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* Function to shuffle the elements of an array. (for reference)
|
||||
* @tparam T typename of the array
|
||||
* @tparam N length of array
|
||||
* @param arr array to shuffle
|
||||
* @returns new array with elements shuffled from a given array
|
||||
*/
|
||||
template <typename T, size_t N>
|
||||
std::array <T, N> shuffle (std::array <T, N> arr) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
// Swaps i'th index with random index (less than array size)
|
||||
std::swap(arr[i], arr[std::rand() % N]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
/**
|
||||
* Implement randomized Bogosort algorithm and sort the elements of a given array.
|
||||
* @tparam T typename of the array
|
||||
* @tparam N length of array
|
||||
* @param arr array to sort
|
||||
* @returns new array with elements sorted from a given array
|
||||
*/
|
||||
template <typename T, size_t N>
|
||||
std::array <T, N> randomized_bogosort (std::array <T, N> arr) {
|
||||
// Untill array is not sorted
|
||||
std::random_device random_device;
|
||||
std::mt19937 generator(random_device());
|
||||
while (!std::is_sorted(arr.begin(), arr.end())) {
|
||||
std::shuffle(arr.begin(), arr.end(), generator);// Shuffle the array
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* Function to display array on screen
|
||||
* @tparam T typename of the array
|
||||
* @tparam N length of array
|
||||
* @param arr array to display
|
||||
*/
|
||||
template <typename T, size_t N>
|
||||
void show_array (const std::array <T, N> &arr) {
|
||||
for (int x : arr) {
|
||||
std::cout << x << ' ';
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to test above algorithm
|
||||
*/
|
||||
void test() {
|
||||
// Test 1
|
||||
std::array <int, 5> arr1;
|
||||
for (int &x : arr1) {
|
||||
x = std::rand() % 100;
|
||||
}
|
||||
std::cout << "Original Array : ";
|
||||
show_array(arr1);
|
||||
arr1 = sorting::randomized_bogosort(arr1);
|
||||
std::cout << "Sorted Array : ";
|
||||
show_array(arr1);
|
||||
assert(std::is_sorted(arr1.begin(), arr1.end()));
|
||||
// Test 2
|
||||
std::array <int, 5> arr2;
|
||||
for (int &x : arr2) {
|
||||
x = std::rand() % 100;
|
||||
}
|
||||
std::cout << "Original Array : ";
|
||||
show_array(arr2);
|
||||
arr2 = sorting::randomized_bogosort(arr2);
|
||||
std::cout << "Sorted Array : ";
|
||||
show_array(arr2);
|
||||
assert(std::is_sorted(arr2.begin(), arr2.end()));
|
||||
}
|
||||
|
||||
/** Driver Code */
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
// Example Usage
|
||||
std::array <int, 5> arr = {3, 7, 10, 4, 1}; // Defining array which we want to sort
|
||||
std::cout << "Original Array : ";
|
||||
show_array(arr);
|
||||
arr = sorting::randomized_bogosort(arr); // Callling bogo sort on it
|
||||
std::cout << "Sorted Array : ";
|
||||
show_array(arr); // Printing sorted array
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Bubble sort algorithm
|
||||
*
|
||||
* @details
|
||||
* Bubble sort algorithm is the bubble sorting algorithm. The most important reason
|
||||
* for calling the bubble is that the largest number is thrown at the end of this
|
||||
* algorithm. This is all about the logic. In each iteration, the largest number is
|
||||
* expired and when iterations are completed, the sorting takes place.
|
||||
*
|
||||
* What is Swap?
|
||||
*
|
||||
* Swap in the software means that two variables are displaced.
|
||||
* An additional variable is required for this operation. x = 5, y = 10.
|
||||
* We want x = 10, y = 5. Here we create the most variable to do it.
|
||||
*
|
||||
* ```cpp
|
||||
* int z;
|
||||
* z = x;
|
||||
* x = y;
|
||||
* y = z;
|
||||
* ```
|
||||
*
|
||||
* The above process is a typical displacement process.
|
||||
* When x assigns the value to x, the old value of x is lost.
|
||||
* That's why we created a variable z to create the first value of the value of x,
|
||||
* and finally, we have assigned to y.
|
||||
*
|
||||
* ## Bubble Sort Algorithm Analysis (Best Case - Worst Case - Average Case)
|
||||
*
|
||||
* ### Best Case
|
||||
* Bubble Sort Best Case Performance. \f$O(n)\f$. However, you
|
||||
* can't get the best status in the code we shared above. This happens on the
|
||||
* optimized bubble sort algorithm. It's right down there.
|
||||
*
|
||||
* ### Worst Case
|
||||
* Bubble Sort Worst Case Performance is \f$O(n^{2})\f$. Why is that? Because if you
|
||||
* remember Big O Notation, we were calculating the complexity of the algorithms in
|
||||
* the nested loops. The \f$n * (n - 1)\f$ product gives us \f$O(n^{2})\f$ performance. In the
|
||||
* worst case all the steps of the cycle will occur.
|
||||
*
|
||||
* ### Average Case
|
||||
* Bubble Sort is not an optimal algorithm. In average, \f$O(n^{2})\f$ performance is taken.
|
||||
*
|
||||
* @author [Deepak](https://github.com/Deepak-j-p)
|
||||
* @author [Nguyen Phuc Chuong](https://github.com/hollowcrust)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::is_sorted
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO implementations
|
||||
#include <string> /// for std::string
|
||||
#include <utility> /// for std::pair, std::swap
|
||||
#include <vector> /// for std::vector, std::vector::push_back, std::vector::size
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace bubble_sort
|
||||
* @brief Bubble sort algorithm
|
||||
*/
|
||||
namespace bubble_sort {
|
||||
/**
|
||||
* @brief Bubble sort algorithm
|
||||
* @param array An array to be sorted
|
||||
* @return The array sorted in ascending order
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<T> bubble_sort(std::vector<T>& array) {
|
||||
// swap_check flag to terminate the function early
|
||||
// if there is no swap occurs in one iteration.
|
||||
bool swap_check = true;
|
||||
int size = array.size();
|
||||
for (int i = 0; (i < size) && (swap_check); i++) {
|
||||
swap_check = false;
|
||||
for (int j = 0; j < size - 1 - i; j++) {
|
||||
if (array[j] > array[j + 1]) {
|
||||
swap_check = true;
|
||||
std::swap(array[j], array[j + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
} // namespace bubble_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Self-test implementation
|
||||
* @return void
|
||||
*/
|
||||
static void test() {
|
||||
std::vector<int> vec_1 = {3, 1, -9, 0};
|
||||
std::vector<int> sorted_1 = sorting::bubble_sort::bubble_sort(vec_1);
|
||||
|
||||
std::vector<int> vec_2 = {3};
|
||||
std::vector<int> sorted_2 = sorting::bubble_sort::bubble_sort(vec_2);
|
||||
|
||||
std::vector<int> vec_3 = {10, 10, 10, 10, 10};
|
||||
std::vector<int> sorted_3 = sorting::bubble_sort::bubble_sort(vec_3);
|
||||
|
||||
std::vector<float> vec_4 = {1234, -273.1, 23, 150, 1234, 1555.55, -2000};
|
||||
std::vector<float> sorted_4 = sorting::bubble_sort::bubble_sort(vec_4);
|
||||
|
||||
std::vector<char> vec_5 = {'z', 'Z', 'a', 'B', ' ', 'c', 'a'};
|
||||
std::vector<char> sorted_5 = sorting::bubble_sort::bubble_sort(vec_5);
|
||||
|
||||
std::vector<std::string> vec_6 = {"Hello", "hello", "Helo", "Hi", "hehe"};
|
||||
std::vector<std::string> sorted_6 = sorting::bubble_sort::bubble_sort(vec_6);
|
||||
|
||||
std::vector<std::pair<int, char>> vec_7 = {{10, 'c'}, {2, 'z'}, {10, 'a'}, {0, 'b'}, {-1, 'z'}};
|
||||
std::vector<std::pair<int, char>> sorted_7 = sorting::bubble_sort::bubble_sort(vec_7);
|
||||
|
||||
assert(std::is_sorted(sorted_1.begin(), sorted_1.end()));
|
||||
assert(std::is_sorted(sorted_2.begin(), sorted_2.end()));
|
||||
assert(std::is_sorted(sorted_3.begin(), sorted_3.end()));
|
||||
assert(std::is_sorted(sorted_4.begin(), sorted_4.end()));
|
||||
assert(std::is_sorted(sorted_5.begin(), sorted_5.end()));
|
||||
assert(std::is_sorted(sorted_6.begin(), sorted_6.end()));
|
||||
assert(std::is_sorted(sorted_7.begin(), sorted_7.end()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @return 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// C++ program to sort an array using bucket sort
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// Function to sort arr[] of size n using bucket sort
|
||||
void bucketSort(float arr[], int n) {
|
||||
// 1) Create n empty buckets
|
||||
std::vector<float> *b = new std::vector<float>[n];
|
||||
|
||||
// 2) Put array elements in different buckets
|
||||
for (int i = 0; i < n; i++) {
|
||||
int bi = n * arr[i]; // Index in bucket
|
||||
b[bi].push_back(arr[i]);
|
||||
}
|
||||
|
||||
// 3) Sort individual buckets
|
||||
for (int i = 0; i < n; i++) std::sort(b[i].begin(), b[i].end());
|
||||
|
||||
// 4) Concatenate all buckets into arr[]
|
||||
int index = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
for (int j = 0; j < b[i].size(); j++) arr[index++] = b[i][j];
|
||||
delete[] b;
|
||||
}
|
||||
|
||||
/* Driver program to test above funtion */
|
||||
int main() {
|
||||
float arr[] = {0.897, 0.565, 0.656, 0.1234, 0.665, 0.3434};
|
||||
int n = sizeof(arr) / sizeof(arr[0]);
|
||||
bucketSort(arr, n);
|
||||
|
||||
std::cout << "Sorted array is \n";
|
||||
for (int i = 0; i < n; i++) std::cout << arr[i] << " ";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// Returns Sorted elements after performing Cocktail Selection Sort
|
||||
// It is a Sorting algorithm which chooses the minimum and maximum element in an
|
||||
// array simultaneously, and swaps it with the lowest and highest available
|
||||
// position iteratively or recursively
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// Iterative Version
|
||||
|
||||
void CocktailSelectionSort(std::vector<int> *vec, int low, int high) {
|
||||
while (low <= high) {
|
||||
int minimum = (*vec)[low];
|
||||
int minimumindex = low;
|
||||
int maximum = (*vec)[high];
|
||||
int maximumindex = high;
|
||||
|
||||
for (int i = low; i <= high; i++) {
|
||||
if ((*vec)[i] >= maximum) {
|
||||
maximum = (*vec)[i];
|
||||
maximumindex = i;
|
||||
}
|
||||
if ((*vec)[i] <= minimum) {
|
||||
minimum = (*vec)[i];
|
||||
minimumindex = i;
|
||||
}
|
||||
}
|
||||
if (low != maximumindex || high != minimumindex) {
|
||||
std::swap((*vec)[low], (*vec)[minimumindex]);
|
||||
std::swap((*vec)[high], (*vec)[maximumindex]);
|
||||
} else {
|
||||
std::swap((*vec)[low], (*vec)[high]);
|
||||
}
|
||||
|
||||
low++;
|
||||
high--;
|
||||
}
|
||||
}
|
||||
|
||||
// Recursive Version
|
||||
|
||||
void CocktailSelectionSort_v2(std::vector<int> *vec, int low, int high) {
|
||||
if (low >= high)
|
||||
return;
|
||||
|
||||
int minimum = (*vec)[low];
|
||||
int minimumindex = low;
|
||||
int maximum = (*vec)[high];
|
||||
int maximumindex = high;
|
||||
|
||||
for (int i = low; i <= high; i++) {
|
||||
if ((*vec)[i] >= maximum) {
|
||||
maximum = (*vec)[i];
|
||||
maximumindex = i;
|
||||
}
|
||||
if ((*vec)[i] <= minimum) {
|
||||
minimum = (*vec)[i];
|
||||
minimumindex = i;
|
||||
}
|
||||
}
|
||||
if (low != maximumindex || high != minimumindex) {
|
||||
std::swap((*vec)[low], (*vec)[minimumindex]);
|
||||
std::swap((*vec)[high], (*vec)[maximumindex]);
|
||||
} else {
|
||||
std::swap((*vec)[low], (*vec)[high]);
|
||||
}
|
||||
|
||||
CocktailSelectionSort(vec, low + 1, high - 1);
|
||||
}
|
||||
|
||||
// main function, select any one of iterative or recursive version
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
std::cout << "Enter number of elements\n";
|
||||
std::cin >> n;
|
||||
std::vector<int> v(n);
|
||||
std::cout << "Enter all the elements\n";
|
||||
for (int i = 0; i < n; ++i) {
|
||||
std::cin >> v[i];
|
||||
}
|
||||
|
||||
int method;
|
||||
std::cout << "Enter method: \n\t0: iterative\n\t1: recursive:\t";
|
||||
std::cin >> method;
|
||||
|
||||
if (method == 0) {
|
||||
CocktailSelectionSort(&v, 0, n - 1);
|
||||
} else if (method == 1) {
|
||||
CocktailSelectionSort_v2(&v, 0, n - 1);
|
||||
} else {
|
||||
std::cerr << "Unknown method" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "Sorted elements are\n";
|
||||
for (int i = 0; i < n; ++i) {
|
||||
std::cout << v[i] << " ";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
*
|
||||
* \file
|
||||
* \brief [Comb Sort Algorithm
|
||||
* (Comb Sort)](https://en.wikipedia.org/wiki/Comb_sort)
|
||||
*
|
||||
* \author
|
||||
*
|
||||
* \details
|
||||
* - A better version of bubble sort algorithm
|
||||
* - Bubble sort compares adjacent values whereas comb sort uses gap larger
|
||||
* than 1
|
||||
* - Best case Time complexity O(n)
|
||||
* Worst case Time complexity O(n^2)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
*
|
||||
* Find the next gap by shrinking the current gap by shrink factor of 1.3
|
||||
* @param gap current gap
|
||||
* @return new gap
|
||||
*
|
||||
*/
|
||||
int FindNextGap(int gap) {
|
||||
gap = (gap * 10) / 13;
|
||||
|
||||
return std::max(1, gap);
|
||||
}
|
||||
|
||||
/** Function to sort array
|
||||
*
|
||||
* @param arr array to be sorted
|
||||
* @param l start index of array
|
||||
* @param r end index of array
|
||||
*
|
||||
*/
|
||||
void CombSort(int *arr, int l, int r) {
|
||||
/**
|
||||
*
|
||||
* initial gap will be maximum and the maximum possible value is
|
||||
* the size of the array that is n and which is equal to r in this
|
||||
* case so to avoid passing an extra parameter n that is the size of
|
||||
* the array we are using r to initialize the initial gap.
|
||||
*
|
||||
*/
|
||||
int gap = r;
|
||||
|
||||
/// Initialize swapped as true to make sure that loop runs
|
||||
bool swapped = true;
|
||||
|
||||
/// Keep running until gap = 1 or none elements were swapped
|
||||
while (gap != 1 || swapped) {
|
||||
/// Find next gap
|
||||
gap = FindNextGap(gap);
|
||||
|
||||
swapped = false;
|
||||
|
||||
/// Compare all elements with current gap
|
||||
for (int i = l; i < r - gap; ++i) {
|
||||
if (arr[i] > arr[i + gap]) {
|
||||
std::swap(arr[i], arr[i + gap]);
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tests() {
|
||||
/// Test 1
|
||||
int arr1[10] = {34, 56, 6, 23, 76, 34, 76, 343, 4, 76};
|
||||
CombSort(arr1, 0, 10);
|
||||
assert(std::is_sorted(arr1, arr1 + 10));
|
||||
std::cout << "Test 1 passed\n";
|
||||
|
||||
/// Test 2
|
||||
int arr2[8] = {-6, 56, -45, 56, 0, -1, 8, 8};
|
||||
CombSort(arr2, 0, 8);
|
||||
assert(std::is_sorted(arr2, arr2 + 8));
|
||||
std::cout << "Test 2 Passed\n";
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
/// Running predefined tests
|
||||
tests();
|
||||
|
||||
/// For user interaction
|
||||
int n;
|
||||
std::cin >> n;
|
||||
int *arr = new int[n];
|
||||
for (int i = 0; i < n; ++i) std::cin >> arr[i];
|
||||
CombSort(arr, 0, n);
|
||||
for (int i = 0; i < n; ++i) std::cout << arr[i] << ' ';
|
||||
delete[] arr;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Counting Inversions using [Merge
|
||||
Sort](https://en.wikipedia.org/wiki/Merge_sort)
|
||||
*
|
||||
* @details
|
||||
* Program to count the number of inversions in an array
|
||||
* using merge-sort.
|
||||
*
|
||||
* The count of inversions help to determine how close the array
|
||||
* is to be sorted in ASCENDING order.
|
||||
*
|
||||
* two elements a[i] and a[j] form an inversion if `a[i]` > `a[j]` and i < j
|
||||
*
|
||||
* Time Complexity --> `O(n.log n)`
|
||||
|
||||
* Space Complexity --> `O(n)` ; additional array `temp[1..n]`
|
||||
* ### Algorithm
|
||||
|
||||
* 1. The idea is similar to merge sort, divide the array into two equal or
|
||||
almost
|
||||
* equal halves in each step until the base case is reached.
|
||||
* 2. Create a function merge that counts the number of inversions when two
|
||||
halves of
|
||||
* the array are merged, create two indices i and j, i is the index for
|
||||
first half
|
||||
* and j is an index of the second half. if `a[i]` is greater than `a[j]`,
|
||||
then there are (mid – i)
|
||||
* inversions, Because left and right subarrays are sorted, so all the
|
||||
remaining elements
|
||||
* in left-subarray (a[i+1], a[i+2] … a[mid]) will be greater than a[j].
|
||||
* 3. Create a recursive function to divide the array into halves and find the
|
||||
answer by summing
|
||||
* the number of inversions is the first half, number of inversion in the
|
||||
second half and
|
||||
* the number of inversions by merging the two.
|
||||
* 4. The base case of recursion is when there is only one element in the
|
||||
given half.
|
||||
* 5. Print the answer
|
||||
*
|
||||
* @author [Rakshit Raj](https://github.com/rakshitraj)
|
||||
*/
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint> /// for typedef datatype uint64_t
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace inversion
|
||||
* @brief Functions for counting inversions using Merge Sort algorithm
|
||||
*/
|
||||
namespace inversion {
|
||||
|
||||
// Functions used --->
|
||||
// int mergeSort(int* arr, int* temp, int left, int right);
|
||||
// int merge(int* arr, int* temp, int left, int mid, int right);
|
||||
// int countInversion(int* arr, const int size);
|
||||
// void show(int* arr, const int size);
|
||||
|
||||
/**
|
||||
* @brief Function to merge two sub-arrays.
|
||||
*
|
||||
* @details
|
||||
* merge() function is called from mergeSort()
|
||||
* to merge the array after it split for sorting
|
||||
* by the mergeSort() funtion.
|
||||
*
|
||||
* In this case the merge fuction will also count and return
|
||||
* inversions detected when merging the sub arrays.
|
||||
*
|
||||
* @param arr input array, data-menber of vector
|
||||
* @param temp stores the resultant merged array
|
||||
* @param left lower bound of `arr[]` and left-sub-array
|
||||
* @param mid midpoint, upper bound of left sub-array,
|
||||
* `(mid+1)` gives the lower bound of right-sub-array
|
||||
* @param right upper bound of `arr[]` and right-sub-array
|
||||
* @returns number of inversions found in merge step
|
||||
*/
|
||||
template <typename T>
|
||||
uint32_t merge(T* arr, T* temp, uint32_t left, uint32_t mid, uint32_t right) {
|
||||
uint32_t i = left; /* i --> index of left sub-array */
|
||||
uint32_t j = mid + 1; /* j --> index for right sub-array */
|
||||
uint32_t k = left; /* k --> index for resultant array temp */
|
||||
uint32_t inv_count = 0; // inversion count
|
||||
|
||||
while ((i <= mid) && (j <= right)) {
|
||||
if (arr[i] <= arr[j]) {
|
||||
temp[k++] = arr[i++];
|
||||
} else {
|
||||
temp[k++] = arr[j++];
|
||||
inv_count +=
|
||||
(mid - i +
|
||||
1); // tricky; may vary depending on selection of sub-array
|
||||
}
|
||||
}
|
||||
// Add remaining elements from the larger subarray to the end of temp
|
||||
while (i <= mid) {
|
||||
temp[k++] = arr[i++];
|
||||
}
|
||||
while (j <= right) {
|
||||
temp[k++] = arr[j++];
|
||||
}
|
||||
// Copy temp[] to arr[]
|
||||
for (k = left; k <= right; k++) {
|
||||
arr[k] = temp[k];
|
||||
}
|
||||
return inv_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implement merge Sort and count inverions while merging
|
||||
*
|
||||
* @details
|
||||
* The mergeSort() function implements Merge Sort, a
|
||||
* Divide and conquer algorithm, it divides the input
|
||||
* array into two halves and calls itself for each
|
||||
* sub-array and then calls the merge() function to
|
||||
* merge the two halves.
|
||||
*
|
||||
* @param arr - array to be sorted
|
||||
* @param temp - merged resultant array
|
||||
* @param left - lower bound of array
|
||||
* @param right - upper bound of array
|
||||
* @returns number of inversions in array
|
||||
*/
|
||||
template <typename T>
|
||||
uint32_t mergeSort(T* arr, T* temp, uint32_t left, uint32_t right) {
|
||||
uint32_t mid = 0, inv_count = 0;
|
||||
if (right > left) {
|
||||
// midpoint to split the array
|
||||
mid = (right + left) / 2;
|
||||
// Add inversions in left and right sub-arrays
|
||||
inv_count += mergeSort(arr, temp, left, mid); // left sub-array
|
||||
inv_count += mergeSort(arr, temp, mid + 1, right);
|
||||
|
||||
// inversions in the merge step
|
||||
inv_count += merge(arr, temp, left, mid, right);
|
||||
}
|
||||
return inv_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function countInversion() returns the number of inversion
|
||||
* present in the input array. Inversions are an estimate of
|
||||
* how close or far off the array is to being sorted.
|
||||
*
|
||||
* @details
|
||||
* Number of inversions in a sorted array is 0.
|
||||
* Number of inversion in an array[1...n] sorted in
|
||||
* non-ascending order is n(n-1)/2, since each pair of elements
|
||||
* contitute an inversion.
|
||||
*
|
||||
* @param arr - array, data member of std::vector<int>, input for counting
|
||||
* inversions
|
||||
* @param array_size - number of elementa in the array
|
||||
* @returns number of inversions in input array, sorts the array
|
||||
*/
|
||||
template <class T>
|
||||
uint32_t countInversion(T* arr, const uint32_t size) {
|
||||
std::vector<T> temp;
|
||||
temp.reserve(size);
|
||||
temp.assign(size, 0);
|
||||
return mergeSort(arr, temp.data(), 0, size - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UTILITY function to print array.
|
||||
* @param arr[] array to print
|
||||
* @param array_size size of input array arr[]
|
||||
* @returns void
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
void show(T* arr, const uint32_t array_size) {
|
||||
std::cout << "Printing array: \n";
|
||||
for (uint32_t i = 0; i < array_size; i++) {
|
||||
std::cout << " " << arr[i];
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
} // namespace inversion
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test 1
|
||||
std::vector<uint64_t> arr1 = {
|
||||
100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84,
|
||||
83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67,
|
||||
66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50,
|
||||
49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
|
||||
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
|
||||
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
|
||||
uint32_t size1 = arr1.size();
|
||||
uint32_t inv_count1 = 4950;
|
||||
uint32_t result1 = sorting::inversion::countInversion(arr1.data(), size1);
|
||||
assert(inv_count1 == result1);
|
||||
// Test 2
|
||||
std::vector<int> arr2 = {22, 66, 75, 23, 11, 87, 2, 44, 98, 43};
|
||||
uint32_t size2 = arr2.size();
|
||||
uint32_t inv_count2 = 20;
|
||||
uint32_t result2 = sorting::inversion::countInversion(arr2.data(), size2);
|
||||
assert(inv_count2 == result2);
|
||||
// Test 3
|
||||
std::vector<double> arr3 = {33.1, 45.2, 65.4, 76.5, 1.0,
|
||||
2.9, 5.4, 7.7, 88.9, 12.4};
|
||||
uint32_t size3 = arr3.size();
|
||||
uint32_t inv_count3 = 21;
|
||||
uint32_t result3 = sorting::inversion::countInversion(arr3.data(), size3);
|
||||
assert(inv_count3 == result3);
|
||||
// Test 4
|
||||
std::vector<char> arr4 = {'a', 'b', 'c', 'd', 'e'};
|
||||
uint32_t size4 = arr4.size();
|
||||
uint32_t inv_count4 = 0;
|
||||
uint32_t result4 = sorting::inversion::countInversion(arr4.data(), size4);
|
||||
assert(inv_count4 == result4);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @brief Program Body contains all main funtionality
|
||||
// * @returns void
|
||||
// */
|
||||
// template <typename T>
|
||||
// static void body() {
|
||||
// // Input your own sequence
|
||||
// uint_t size;
|
||||
// T input;
|
||||
// std::cout << "Enter number of elements:";
|
||||
// std::cin >> size;
|
||||
//
|
||||
// std::vector<T> arr;
|
||||
// arr.reserve(size);
|
||||
//
|
||||
// std::cout << "Enter elements -->\n";
|
||||
// for (uint64_t i=1; i<=size; i++) {
|
||||
// std::cout << "Element "<< i <<" :";
|
||||
// std::cin >> input;
|
||||
// arr.push_back(input);
|
||||
// }
|
||||
//
|
||||
// if (size != arr.size()) {
|
||||
// size = arr.size();
|
||||
// }
|
||||
//
|
||||
// std::cout << "\n";
|
||||
// sorting::inversion::show(arr.data(), size);
|
||||
// std::cout << "\n";
|
||||
//
|
||||
// // Counting inversions
|
||||
// std::cout << "\nThe number of inversions: "<<
|
||||
// sorting::inversion::countInversion(arr.data(), size) << "\n";
|
||||
//
|
||||
// // Output sorted array
|
||||
// std::cout << "\nSorted array --> \n";
|
||||
// sorting::inversion::show(arr.data(), size);
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // Run test implementations
|
||||
// body(); // test your own array
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int Max(int Arr[], int N) {
|
||||
int max = Arr[0];
|
||||
for (int i = 1; i < N; i++)
|
||||
if (Arr[i] > max)
|
||||
max = Arr[i];
|
||||
return max;
|
||||
}
|
||||
|
||||
int Min(int Arr[], int N) {
|
||||
int min = Arr[0];
|
||||
for (int i = 1; i < N; i++)
|
||||
if (Arr[i] < min)
|
||||
min = Arr[i];
|
||||
return min;
|
||||
}
|
||||
|
||||
void Print(int Arr[], int N) {
|
||||
for (int i = 0; i < N; i++) cout << Arr[i] << ", ";
|
||||
}
|
||||
|
||||
int *Counting_Sort(int Arr[], int N) {
|
||||
int max = Max(Arr, N);
|
||||
int min = Min(Arr, N);
|
||||
int *Sorted_Arr = new int[N];
|
||||
|
||||
int *Count = new int[max - min + 1];
|
||||
for (int i = 0; i < max - min + 1; ++i) {
|
||||
Count[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; i++) Count[Arr[i] - min]++;
|
||||
|
||||
for (int i = 1; i < (max - min + 1); i++) Count[i] += Count[i - 1];
|
||||
|
||||
for (int i = N - 1; i >= 0; i--) {
|
||||
Sorted_Arr[Count[Arr[i] - min] - 1] = Arr[i];
|
||||
Count[Arr[i] - min]--;
|
||||
}
|
||||
|
||||
delete[] Count;
|
||||
return Sorted_Arr;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int Arr[] = {47, 65, 20, 66, 25, 53, 64, 69, 72, 22,
|
||||
74, 25, 53, 15, 42, 36, 4, 69, 86, 19},
|
||||
N = 20;
|
||||
int *Sorted_Arr;
|
||||
|
||||
cout << "\n\tOrignal Array = ";
|
||||
Print(Arr, N);
|
||||
Sorted_Arr = Counting_Sort(Arr, N);
|
||||
cout << "\n\t Sorted Array = ";
|
||||
Print(Sorted_Arr, N);
|
||||
delete[] Sorted_Arr;
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// C++ Program for counting sort
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void countSort(string arr) {
|
||||
string output;
|
||||
|
||||
int count[256], i;
|
||||
for (int i = 0; i < 256; i++) count[i] = 0;
|
||||
|
||||
for (i = 0; arr[i]; ++i) ++count[arr[i]];
|
||||
|
||||
for (i = 1; i < 256; ++i) count[i] += count[i - 1];
|
||||
|
||||
for (i = 0; arr[i]; ++i) {
|
||||
output[count[arr[i]] - 1] = arr[i];
|
||||
--count[arr[i]];
|
||||
}
|
||||
|
||||
for (i = 0; arr[i]; ++i) arr[i] = output[i];
|
||||
|
||||
cout << "Sorted character array is " << arr;
|
||||
}
|
||||
|
||||
int main() {
|
||||
string arr;
|
||||
cin >> arr;
|
||||
|
||||
countSort(arr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Cycle
|
||||
* sort](https://en.wikipedia.org/wiki/Cycle_sort) algorithm
|
||||
* @details
|
||||
* Cycle Sort is a sorting algorithm that works in \f$O(n^2)\f$ time in the best
|
||||
* case and works in \f$O(n^2)\f$ in worst case. If a element is already at its
|
||||
* correct position, do nothing. If a element is not at its correct position,
|
||||
* we then need to move it to its correct position by computing the correct
|
||||
* positions.Therefore, we should make sure the duplicate elements.
|
||||
* @author [TsungHan Ho](https://github.com/dalaoqi)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::is_sorted, std::swap
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for io operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace cycle_sort
|
||||
* @brief Functions for [Cycle sort](https://en.wikipedia.org/wiki/Cycle_sort)
|
||||
* algorithm
|
||||
*/
|
||||
namespace cycle_sort {
|
||||
/**
|
||||
* @brief The main function implements cycleSort
|
||||
* @tparam T type of array
|
||||
* @param in_arr array to be sorted
|
||||
* @returns void
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<T> cycleSort(const std::vector<T> &in_arr) {
|
||||
std::vector<T> arr(in_arr);
|
||||
for (int cycle_start = 0; cycle_start <= arr.size() - 1; cycle_start++) {
|
||||
// initialize item
|
||||
T item = arr[cycle_start];
|
||||
|
||||
// Count the number of elements smaller than item, this number is the
|
||||
// correct index of item.
|
||||
int pos = cycle_start;
|
||||
for (int i = cycle_start + 1; i < arr.size(); i++) {
|
||||
if (arr[i] < item) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
// item is already in correct position
|
||||
if (pos == cycle_start) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// duplicate elements
|
||||
while (item == arr[pos]) pos += 1;
|
||||
if (pos == cycle_start) {
|
||||
continue;
|
||||
} else {
|
||||
std::swap(item, arr[pos]);
|
||||
}
|
||||
// Rest of the elements
|
||||
while (pos != cycle_start) {
|
||||
pos = cycle_start;
|
||||
// Find position where we put the element
|
||||
for (size_t i = cycle_start + 1; i < arr.size(); i++) {
|
||||
if (arr[i] < item) {
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
// duplicate elements
|
||||
while (item == arr[pos]) pos += 1;
|
||||
if (item == arr[pos]) {
|
||||
continue;
|
||||
} else {
|
||||
std::swap(item, arr[pos]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
} // namespace cycle_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test 1
|
||||
// [4, 3, 2, 1] return [1, 2, 3, 4]
|
||||
std::vector<uint32_t> array1 = {4, 3, 2, 1};
|
||||
std::cout << "Test 1... ";
|
||||
std::vector<uint32_t> arr1 = sorting::cycle_sort::cycleSort(array1);
|
||||
assert(std::is_sorted(std::begin(arr1), std::end(arr1)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// [4.3, -6.5, -7.4, 0, 2.7, 1.8] return [-7.4, -6.5, 0, 1.8, 2.7, 4.3]
|
||||
std::vector<double> array2 = {4.3, -6.5, -7.4, 0, 2.7, 1.8};
|
||||
std::cout << "Test 2... ";
|
||||
std::vector<double> arr2 = sorting::cycle_sort::cycleSort(array2);
|
||||
assert(std::is_sorted(std::begin(arr2), std::end(arr2)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 3
|
||||
// [3, 3, 3, 3] return [3, 3, 3, 3]
|
||||
std::vector<uint32_t> array3 = {3, 3, 3, 3};
|
||||
std::cout << "Test 3... ";
|
||||
std::vector<uint32_t> arr3 = sorting::cycle_sort::cycleSort(array3);
|
||||
assert(std::is_sorted(std::begin(arr3), std::end(arr3)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// [9, 4, 6, 8, 14, 3] return [9, 4, 6, 8, 14, 3]
|
||||
std::vector<uint32_t> array4 = {3, 4, 6, 8, 9, 14};
|
||||
std::cout << "Test 4... ";
|
||||
std::vector<uint32_t> arr4 = sorting::cycle_sort::cycleSort(array4);
|
||||
assert(std::is_sorted(std::begin(arr4), std::end(arr4)));
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // execute the test
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [DNF
|
||||
* sort](https://www.geeksforgeeks.org/sort-an-array-of-0s-1s-and-2s/)
|
||||
* implementation
|
||||
* @details
|
||||
* C++ program to sort an array with 0, 1 and 2 in a single pass(DNF sort).
|
||||
* Since one traversal of the array is there hence it works in O(n) time
|
||||
* complexity.
|
||||
* @author [Sujal Gupta](https://github.com/heysujal)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::is_sorted
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for std::swap and io operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @breif Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace dnf_sort
|
||||
* @brief Functions for the [DNF
|
||||
* sort](https://en.wikipedia.org/wiki/Dutch_national_flag_problem)
|
||||
* implementation
|
||||
*/
|
||||
namespace dnf_sort {
|
||||
/**
|
||||
* @brief The main function implements DNF sort
|
||||
* @tparam T type of array
|
||||
* @param a array to be sorted,
|
||||
* @param arr_size size of array
|
||||
* @returns void
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<T> dnfSort(const std::vector<T> &in_arr) {
|
||||
std::vector<T> arr(in_arr);
|
||||
uint64_t lo = 0;
|
||||
uint64_t hi = arr.size() - 1;
|
||||
uint64_t mid = 0;
|
||||
|
||||
// Iterate till all the elements
|
||||
// are sorted
|
||||
while (mid <= hi) {
|
||||
switch (arr[mid]) {
|
||||
// If the element is 0
|
||||
case 0:
|
||||
std::swap(arr[lo++], arr[mid++]);
|
||||
break;
|
||||
|
||||
// If the element is 1 .
|
||||
case 1:
|
||||
mid++;
|
||||
break;
|
||||
|
||||
// If the element is 2
|
||||
case 2:
|
||||
std::swap(arr[mid], arr[hi--]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
} // namespace dnf_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
// [1, 0, 2, 1] return [0, 1, 1, 2]
|
||||
std::vector<uint64_t> array1 = {0, 1, 1, 2};
|
||||
std::cout << "Test 1... ";
|
||||
std::vector<uint64_t> arr1 = sorting::dnf_sort::dnfSort(array1);
|
||||
assert(std::is_sorted(std::begin(arr1), std::end(arr1)));
|
||||
std::cout << "passed" << std::endl;
|
||||
// 2nd test
|
||||
// [1, 0, 0, 1, 1, 0, 2, 1] return [0, 0, 0, 1, 1, 1, 1, 2]
|
||||
std::vector<uint64_t> array2 = {1, 0, 0, 1, 1, 0, 2, 1};
|
||||
std::cout << "Test 2... ";
|
||||
std::vector<uint64_t> arr2 = sorting::dnf_sort::dnfSort(array2);
|
||||
assert(std::is_sorted(std::begin(arr2), std::end(arr2)));
|
||||
std::cout << "passed" << std::endl;
|
||||
// 3rd test
|
||||
// [1, 1, 0, 0, 1, 2, 2, 0, 2, 1] return [0, 0, 0, 1, 1, 1, 1, 2, 2, 2]
|
||||
std::vector<uint64_t> array3 = {1, 1, 0, 0, 1, 2, 2, 0, 2, 1};
|
||||
std::cout << "Test 3... ";
|
||||
std::vector<uint64_t> arr3 = sorting::dnf_sort::dnfSort(array3);
|
||||
assert(std::is_sorted(std::begin(arr3), std::end(arr3)));
|
||||
std::cout << "passed" << std::endl;
|
||||
// 4th test
|
||||
// [2, 2, 2, 0, 0, 1, 1] return [0, 0, 1, 1, 2, 2, 2]
|
||||
std::vector<uint64_t> array4 = {2, 2, 2, 0, 0, 1, 1};
|
||||
std::cout << "Test 4... ";
|
||||
std::vector<uint64_t> arr4 = sorting::dnf_sort::dnfSort(array4);
|
||||
assert(std::is_sorted(std::begin(arr4), std::end(arr4)));
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // execute the test
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [gnome
|
||||
* sort](https://en.wikipedia.org/wiki/Gnome_sort) algorithm.
|
||||
* @author [beqakd](https://github.com/beqakd)
|
||||
* @author [Krishna Vedala](https://github.com/kvedala)
|
||||
* @details
|
||||
* Gnome sort algorithm is not the best one but it is widely used.
|
||||
* The algorithm iteratively checks the order of pairs in the array. If they are
|
||||
* on right order it moves to the next successive pair, otherwise it swaps
|
||||
* elements. This operation is repeated until no more swaps are made thus
|
||||
* indicating the values to be in ascending order.
|
||||
*
|
||||
* The time Complexity of the algorithm is \f$O(n^2)\f$ and in some cases it
|
||||
* can be \f$O(n)\f$.
|
||||
*/
|
||||
|
||||
#include <algorithm> // for std::swap
|
||||
#include <array> // for std::array
|
||||
#include <cassert> // for assertions
|
||||
#include <iostream> // for io operations
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* This implementation is for a C-style array input that gets modified in place.
|
||||
* @param [in,out] arr our array of elements.
|
||||
* @param size size of given array
|
||||
*/
|
||||
template <typename T>
|
||||
void gnomeSort(T *arr, int size) {
|
||||
// few easy cases
|
||||
if (size <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int index = 0; // initialize some variables.
|
||||
while (index < size) {
|
||||
// check for swap
|
||||
if ((index == 0) || (arr[index] >= arr[index - 1])) {
|
||||
index++;
|
||||
} else {
|
||||
std::swap(arr[index], arr[index - 1]); // swap
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation is for a C++-style array input. The function argument is
|
||||
* a pass-by-value and hence a copy of the array gets created which is then
|
||||
* modified by the function and returned.
|
||||
* @tparam T type of data variables in the array
|
||||
* @tparam size size of the array
|
||||
* @param [in] arr our array of elements.
|
||||
* @return array with elements sorted
|
||||
*/
|
||||
template <typename T, size_t size>
|
||||
std::array<T, size> gnomeSort(std::array<T, size> arr) {
|
||||
// few easy cases
|
||||
if (size <= 1) {
|
||||
return arr;
|
||||
}
|
||||
|
||||
int index = 0; // initialize loop index
|
||||
while (index < size) {
|
||||
// check for swap
|
||||
if ((index == 0) || (arr[index] >= arr[index - 1])) {
|
||||
index++;
|
||||
} else {
|
||||
std::swap(arr[index], arr[index - 1]); // swap
|
||||
index--;
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* Test function
|
||||
*/
|
||||
static void test() {
|
||||
// Example 1. Creating array of int,
|
||||
std::cout << "Test 1 - as a C-array...";
|
||||
const int size = 6;
|
||||
std::array<int, size> arr = {-22, 100, 150, 35, -10, 99};
|
||||
sorting::gnomeSort(arr.data(),
|
||||
size); // pass array data as a C-style array pointer
|
||||
assert(std::is_sorted(std::begin(arr), std::end(arr)));
|
||||
std::cout << " Passed\n";
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::cout << arr[i] << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example 2. Creating array of doubles.
|
||||
std::cout << "\nTest 2 - as a std::array...";
|
||||
std::array<double, size> double_arr = {-100.2, 10.2, 20.0, 9.0, 7.5, 7.2};
|
||||
std::array<double, size> sorted_arr = sorting::gnomeSort(double_arr);
|
||||
assert(std::is_sorted(std::begin(sorted_arr), std::end(sorted_arr)));
|
||||
std::cout << " Passed\n";
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::cout << double_arr[i] << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example 3. Creating random array of float.
|
||||
std::cout << "\nTest 3 - 200 random numbers as a std::array...";
|
||||
const int size2 = 200;
|
||||
std::array<float, size2> rand_arr{};
|
||||
|
||||
for (auto &a : rand_arr) {
|
||||
// generate random numbers between -5.0 and 4.99
|
||||
a = float(std::rand() % 1000 - 500) / 100.f;
|
||||
}
|
||||
|
||||
std::array<float, size2> float_arr = sorting::gnomeSort(rand_arr);
|
||||
assert(std::is_sorted(std::begin(float_arr), std::end(float_arr)));
|
||||
std::cout << " Passed\n";
|
||||
// for (int i = 0; i < size; i++) std::cout << double_arr[i] << ", ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Our main function with example of sort method.
|
||||
*/
|
||||
int main() {
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief [Heap Sort Algorithm
|
||||
* (heap sort)](https://en.wikipedia.org/wiki/Heapsort) implementation
|
||||
*
|
||||
* \author [Ayaan Khan](http://github.com/ayaankhan98)
|
||||
*
|
||||
* \details
|
||||
* Heap-sort is a comparison-based sorting algorithm.
|
||||
* Heap-sort can be thought of as an improved selection sort:
|
||||
* like selection sort, heap sort divides its input into a sorted
|
||||
* and an unsorted region, and it iteratively shrinks the unsorted
|
||||
* region by extracting the largest element from it and inserting
|
||||
* it into the sorted region. Unlike selection sort,
|
||||
* heap sort does not waste time with a linear-time scan of the
|
||||
* unsorted region; rather, heap sort maintains the unsorted region
|
||||
* in a heap data structure to more quickly find the largest element
|
||||
* in each step.
|
||||
*
|
||||
* Time Complexity - \f$O(n \log(n))\f$
|
||||
*
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
*
|
||||
* Utility function to print the array after
|
||||
* sorting.
|
||||
*
|
||||
* @param arr array to be printed
|
||||
* @param sz size of array
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
void printArray(T *arr, int sz) {
|
||||
for (int i = 0; i < sz; i++) std::cout << arr[i] << " ";
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* \addtogroup sorting Sorting Algorithm
|
||||
* @{
|
||||
*
|
||||
* The heapify procedure can be thought of as building a heap from
|
||||
* the bottom up by successively sifting downward to establish the
|
||||
* heap property.
|
||||
*
|
||||
* @param arr array to be sorted
|
||||
* @param n size of array
|
||||
* @param i node position in Binary Tress or element position in
|
||||
* Array to be compared with it's childern
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
void heapify(T *arr, int n, int i) {
|
||||
int largest = i;
|
||||
int l = 2 * i + 1;
|
||||
int r = 2 * i + 2;
|
||||
|
||||
if (l < n && arr[l] > arr[largest])
|
||||
largest = l;
|
||||
|
||||
if (r < n && arr[r] > arr[largest])
|
||||
largest = r;
|
||||
|
||||
if (largest != i) {
|
||||
std::swap(arr[i], arr[largest]);
|
||||
heapify(arr, n, largest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utilizes heapify procedure to sort
|
||||
* the array
|
||||
*
|
||||
* @param arr array to be sorted
|
||||
* @param n size of array
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
void heapSort(T *arr, int n) {
|
||||
for (int i = n - 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @}
|
||||
* Test cases to test the program
|
||||
*
|
||||
*/
|
||||
void test() {
|
||||
std::cout << "Test 1\n";
|
||||
int arr[] = {-10, 78, -1, -6, 7, 4, 94, 5, 99, 0};
|
||||
int sz = sizeof(arr) / sizeof(arr[0]); // sz - size of array
|
||||
printArray(arr, sz); // displaying the array before sorting
|
||||
heapSort(arr, sz); // calling heapsort to sort the array
|
||||
printArray(arr, sz); // display array after sorting
|
||||
assert(std::is_sorted(arr, arr + sz));
|
||||
std::cout << "Test 1 Passed\n========================\n";
|
||||
|
||||
std::cout << "Test 2\n";
|
||||
double arr2[] = {4.5, -3.6, 7.6, 0, 12.9};
|
||||
sz = sizeof(arr2) / sizeof(arr2[0]);
|
||||
printArray(arr2, sz);
|
||||
heapSort(arr2, sz);
|
||||
printArray(arr2, sz);
|
||||
assert(std::is_sorted(arr2, arr2 + sz));
|
||||
std::cout << "Test 2 passed\n";
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
*
|
||||
* \file
|
||||
* \brief [Insertion Sort Algorithm
|
||||
* (Insertion Sort)](https://en.wikipedia.org/wiki/Insertion_sort)
|
||||
*
|
||||
* \details
|
||||
* Insertion sort is a simple sorting algorithm that builds the final
|
||||
* sorted array one at a time. It is much less efficient compared to
|
||||
* other sorting algorithms like heap sort, merge sort or quick sort.
|
||||
* However it has several advantages such as
|
||||
* 1. Easy to implement
|
||||
* 2. For small set of data it is quite efficient
|
||||
* 3. More efficient that other Quadratic complexity algorithms like
|
||||
* Selection sort or bubble sort.
|
||||
* 4. It's stable that is it does not change the relative order of
|
||||
* elements with equal keys
|
||||
* 5. Works on hand means it can sort the array or list as it receives.
|
||||
*
|
||||
* It is based on the same idea that people use to sort the playing cards in
|
||||
* their hands.
|
||||
* the algorithms goes in the manner that we start iterating over the array
|
||||
* of elements as soon as we find a unsorted element that is a misplaced
|
||||
* element we place it at a sorted position.
|
||||
*
|
||||
* Example execution steps:
|
||||
* 1. Suppose initially we have
|
||||
* \f{bmatrix}{4 &3 &2 &5 &1\f}
|
||||
* 2. We start traversing from 4 till we reach 1
|
||||
* when we reach at 3 we find that it is misplaced so we take 3 and place
|
||||
* it at a correct position thus the array will become
|
||||
* \f{bmatrix}{3 &4 &2 &5 &1\f}
|
||||
* 3. In the next iteration we are at 2 we find that this is also misplaced so
|
||||
* we place it at the correct sorted position thus the array in this iteration
|
||||
* becomes
|
||||
* \f{bmatrix}{2 &3 &4 &5 &1\f}
|
||||
* 4. We do not do anything with 5 and move on to the next iteration and
|
||||
* select 1 which is misplaced and place it at correct position. Thus, we have
|
||||
* \f{bmatrix}{1 &2 &3 &4 &5\f}
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
/** \namespace sorting
|
||||
* \brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/** \brief
|
||||
* Insertion Sort Function
|
||||
*
|
||||
* @tparam T type of array
|
||||
* @param [in,out] arr Array to be sorted
|
||||
* @param n Size of Array
|
||||
*/
|
||||
template <typename T>
|
||||
void insertionSort(T *arr, int n) {
|
||||
for (int i = 1; i < n; i++) {
|
||||
T temp = arr[i];
|
||||
int j = i - 1;
|
||||
while (j >= 0 && temp < arr[j]) {
|
||||
arr[j + 1] = arr[j];
|
||||
j--;
|
||||
}
|
||||
arr[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/** Insertion Sort Function
|
||||
*
|
||||
* @tparam T type of array
|
||||
* @param [in,out] arr pointer to array to be sorted
|
||||
*/
|
||||
template <typename T>
|
||||
void insertionSort(std::vector<T> *arr) {
|
||||
size_t n = arr->size();
|
||||
|
||||
for (size_t i = 1; i < n; i++) {
|
||||
T temp = arr[0][i];
|
||||
int32_t j = i - 1;
|
||||
while (j >= 0 && temp < arr[0][j]) {
|
||||
arr[0][j + 1] = arr[0][j];
|
||||
j--;
|
||||
}
|
||||
arr[0][j + 1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Create a random array objecthelper function to create a random array
|
||||
*
|
||||
* @tparam T type of array
|
||||
* @param arr array to fill (must be pre-allocated)
|
||||
* @param N number of array elements
|
||||
*/
|
||||
template <typename T>
|
||||
static void create_random_array(T *arr, int N) {
|
||||
while (N--) {
|
||||
double r = (std::rand() % 10000 - 5000) / 100.f;
|
||||
arr[N] = static_cast<T>(r);
|
||||
}
|
||||
}
|
||||
|
||||
/** Test Cases to test algorithm */
|
||||
void tests() {
|
||||
int arr1[10] = {78, 34, 35, 6, 34, 56, 3, 56, 2, 4};
|
||||
std::cout << "Test 1... ";
|
||||
sorting::insertionSort(arr1, 10);
|
||||
assert(std::is_sorted(arr1, arr1 + 10));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
int arr2[5] = {5, -3, 7, -2, 1};
|
||||
std::cout << "Test 2... ";
|
||||
sorting::insertionSort(arr2, 5);
|
||||
assert(std::is_sorted(arr2, arr2 + 5));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
float arr3[5] = {5.6, -3.1, -3.0, -2.1, 1.8};
|
||||
std::cout << "Test 3... ";
|
||||
sorting::insertionSort(arr3, 5);
|
||||
assert(std::is_sorted(arr3, arr3 + 5));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
std::vector<float> arr4({5.6, -3.1, -3.0, -2.1, 1.8});
|
||||
std::cout << "Test 4... ";
|
||||
sorting::insertionSort(&arr4);
|
||||
assert(std::is_sorted(std::begin(arr4), std::end(arr4)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
int arr5[50];
|
||||
std::cout << "Test 5... ";
|
||||
create_random_array(arr5, 50);
|
||||
sorting::insertionSort(arr5, 50);
|
||||
assert(std::is_sorted(arr5, arr5 + 50));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
float arr6[50];
|
||||
std::cout << "Test 6... ";
|
||||
create_random_array(arr6, 50);
|
||||
sorting::insertionSort(arr6, 50);
|
||||
assert(std::is_sorted(arr6, arr6 + 50));
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/** Main Function */
|
||||
int main() {
|
||||
/// Running predefined tests to test algorithm
|
||||
tests();
|
||||
|
||||
/// For user insteraction
|
||||
size_t n;
|
||||
std::cout << "Enter the length of your array (0 to exit): ";
|
||||
std::cin >> n;
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int *arr = new int[n];
|
||||
std::cout << "Enter any " << n << " Numbers for Unsorted Array : ";
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::cin >> arr[i];
|
||||
}
|
||||
|
||||
sorting::insertionSort(arr, n);
|
||||
|
||||
std::cout << "\nSorted Array : ";
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::cout << arr[i] << " ";
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
delete[] arr;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Insertion Sort Algorithm
|
||||
* @author [Dhanush S](https://github.com/Fandroid745)
|
||||
*
|
||||
* @details
|
||||
* Insertion sort is a simple sorting algorithm that builds the final
|
||||
* sorted array one element at a time. It is much less efficient compared
|
||||
* to other sorting algorithms like heap sort, merge sort, or quick sort.
|
||||
*
|
||||
* However, it has several advantages:
|
||||
* - Easy to implement.
|
||||
* - Efficient for small data sets.
|
||||
* - More efficient than other O(n²) algorithms like selection sort or bubble sort.
|
||||
* - Stable: it does not change the relative order of elements with equal keys.
|
||||
*
|
||||
* Insertion sort works similarly to how people sort playing cards in their hands.
|
||||
* The algorithm iterates through the list and inserts each element into its correct
|
||||
* position in the sorted portion of the array.
|
||||
*
|
||||
* The time complexity of the algorithm is \f$O(n^2)\f$, and in some cases, it
|
||||
* can be \f$O(n)\f$.
|
||||
*
|
||||
* Example execution:
|
||||
* 1. Start with the array [4, 3, 2, 5, 1].
|
||||
* 2. Insert 3 in its correct position: [3, 4, 2, 5, 1].
|
||||
* 3. Insert 2: [2, 3, 4, 5, 1].
|
||||
* 4. Continue this until the array is sorted: [1, 2, 3, 4, 5].
|
||||
*/
|
||||
|
||||
|
||||
#include <algorithm> /// for std::is_sorted
|
||||
#include <cassert> /// for assert function in testing
|
||||
#include <iostream> /// for std::cout and std::endl
|
||||
#include <vector> /// for using std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Contains sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
|
||||
/**
|
||||
* @brief Insertion Sort Function
|
||||
*
|
||||
* @tparam T Type of the array elements
|
||||
* @param[in,out] arr Array to be sorted
|
||||
* @param n Size of the array
|
||||
*/
|
||||
template <typename T>
|
||||
void insertionSort(T *arr, int n) {
|
||||
for (int i = 1; i < n; i++) {
|
||||
T temp = arr[i];
|
||||
int j = i - 1;
|
||||
while (j >= 0 && temp < arr[j]) {
|
||||
arr[j + 1] = arr[j];
|
||||
j--;
|
||||
}
|
||||
arr[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insertion Sort for a vector
|
||||
*
|
||||
* @tparam T Type of the vector elements
|
||||
* @param [in,out] arr Pointer to the vector to be sorted
|
||||
*/
|
||||
template <typename T>
|
||||
void insertionSort(std::vector<T> *arr) {
|
||||
size_t n = arr->size();
|
||||
|
||||
for (size_t i = 1; i < n; i++) {
|
||||
T temp = arr->at(i);
|
||||
int32_t j = i - 1;
|
||||
while (j >= 0 && temp < arr->at(j)) {
|
||||
arr->at(j + 1) = arr->at(j);
|
||||
j--;
|
||||
}
|
||||
arr->at(j + 1) = temp;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Helper function to create a random array
|
||||
*
|
||||
* @tparam T Type of the array elements
|
||||
* @param arr Array to fill (must be pre-allocated)
|
||||
* @param N Number of elements in the array
|
||||
*/
|
||||
template <typename T>
|
||||
static void create_random_array(T *arr, int N) {
|
||||
while (N--) {
|
||||
double r = (std::rand() % 10000 - 5000) / 100.f;
|
||||
arr[N] = static_cast<T>(r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief self test implementation
|
||||
* @return void
|
||||
*/
|
||||
static void tests() {
|
||||
int arr1[10] = {78, 34, 35, 6, 34, 56, 3, 56, 2, 4};
|
||||
std::cout << "Test 1... ";
|
||||
sorting::insertionSort(arr1, 10);
|
||||
assert(std::is_sorted(arr1, arr1 + 10));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
int arr2[5] = {5, -3, 7, -2, 1};
|
||||
std::cout << "Test 2... ";
|
||||
sorting::insertionSort(arr2, 5);
|
||||
assert(std::is_sorted(arr2, arr2 + 5));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
float arr3[5] = {5.6, -3.1, -3.0, -2.1, 1.8};
|
||||
std::cout << "Test 3... ";
|
||||
sorting::insertionSort(arr3, 5);
|
||||
assert(std::is_sorted(arr3, arr3 + 5));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
std::vector<float> arr4({5.6, -3.1, -3.0, -2.1, 1.8});
|
||||
std::cout << "Test 4... ";
|
||||
sorting::insertionSort(&arr4);
|
||||
assert(std::is_sorted(std::begin(arr4), std::end(arr4)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
int arr5[50];
|
||||
std::cout << "Test 5... ";
|
||||
create_random_array(arr5, 50);
|
||||
sorting::insertionSort(arr5, 50);
|
||||
assert(std::is_sorted(arr5, arr5 + 50));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
float arr6[50];
|
||||
std::cout << "Test 6... ";
|
||||
create_random_array(arr6, 50);
|
||||
sorting::insertionSort(arr6, 50);
|
||||
assert(std::is_sorted(arr6, arr6 + 50));
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @return 0 on successful exit.
|
||||
*/
|
||||
int main() {
|
||||
tests(); /// run self test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
void librarySort(int *index, int n) {
|
||||
int lib_size, index_pos,
|
||||
*gaps, // gaps
|
||||
*library[2]; // libraries
|
||||
|
||||
bool target_lib, *numbered;
|
||||
|
||||
for (int i = 0; i < 2; i++) library[i] = new int[n];
|
||||
|
||||
gaps = new int[n + 1];
|
||||
numbered = new bool[n + 1];
|
||||
|
||||
lib_size = 1;
|
||||
index_pos = 1;
|
||||
target_lib = 0;
|
||||
library[target_lib][0] = index[0];
|
||||
|
||||
while (index_pos < n) {
|
||||
// binary search
|
||||
int insert = std::distance(
|
||||
library[target_lib],
|
||||
std::lower_bound(library[target_lib],
|
||||
library[target_lib] + lib_size, index[index_pos]));
|
||||
|
||||
// if there is no gap to insert a new index ...
|
||||
|
||||
if (numbered[insert] == true) {
|
||||
int prov_size = 0, next_target_lib = !target_lib;
|
||||
|
||||
// update library and clear gaps
|
||||
|
||||
for (int i = 0; i <= n; i++) {
|
||||
if (numbered[i] == true) {
|
||||
library[next_target_lib][prov_size] = gaps[i];
|
||||
prov_size++;
|
||||
numbered[i] = false;
|
||||
}
|
||||
|
||||
if (i <= lib_size) {
|
||||
library[next_target_lib][prov_size] =
|
||||
library[target_lib][i];
|
||||
prov_size++;
|
||||
}
|
||||
}
|
||||
|
||||
target_lib = next_target_lib;
|
||||
lib_size = prov_size - 1;
|
||||
} else {
|
||||
numbered[insert] = true;
|
||||
gaps[insert] = index[index_pos];
|
||||
index_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
int index_pos_for_output = 0;
|
||||
for (int i = 0; index_pos_for_output < n; i++) {
|
||||
if (numbered[i] == true) {
|
||||
// std::cout << gaps[i] << std::endl;
|
||||
index[index_pos_for_output] = gaps[i];
|
||||
index_pos_for_output++;
|
||||
}
|
||||
|
||||
if (i < lib_size) {
|
||||
// std::cout << library[target_lib][i] << std::endl;
|
||||
index[index_pos_for_output] = library[target_lib][i];
|
||||
index_pos_for_output++;
|
||||
}
|
||||
}
|
||||
delete[] numbered;
|
||||
delete[] gaps;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
delete[] library[i];
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// ---example--
|
||||
int index_ex[] = {-6, 5, 9, 1, 9, 1, 0, 1, -8, 4, -12};
|
||||
int n_ex = sizeof(index_ex) / sizeof(index_ex[0]);
|
||||
|
||||
librarySort(index_ex, n_ex);
|
||||
std::cout << "sorted array :" << std::endl;
|
||||
for (int i = 0; i < n_ex; i++) std::cout << index_ex[i] << " ";
|
||||
std::cout << std::endl;
|
||||
|
||||
/* --output--
|
||||
sorted array :
|
||||
-12 -8 -6 0 1 1 1 4 5 9 9
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* @file
|
||||
* @author [@sinkyoungdeok](https://github.com/sinkyoungdeok)
|
||||
* @author [Krishna Vedala](https://github.com/kvedala)
|
||||
* @brief Algorithm that combines insertion sort and merge sort. [Wiki
|
||||
* link](https://en.wikipedia.org/wiki/Merge-insertion_sort)
|
||||
*
|
||||
* @see Individual algorithms: insertion_sort.cpp and merge_sort.cpp
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
/** \namespace sorting
|
||||
* \brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/** \namespace merge_insertion
|
||||
* \brief Combined Intersion-Merge sorting algorithm
|
||||
*/
|
||||
namespace merge_insertion {
|
||||
|
||||
/**
|
||||
* @brief Insertion merge algorithm
|
||||
* @see insertion_sort.cpp
|
||||
*
|
||||
* @tparam T array data type
|
||||
* @tparam N length of array
|
||||
* @param A pointer to array to sort
|
||||
* @param start start index of sorting window
|
||||
* @param end end index of sorting window
|
||||
*/
|
||||
template <typename T, size_t N>
|
||||
static void InsertionSort(std::array<T, N> *A, size_t start, size_t end) {
|
||||
size_t i = 0, j = 0;
|
||||
T *ptr = A->data();
|
||||
|
||||
for (i = start; i < end; i++) {
|
||||
T temp = ptr[i];
|
||||
j = i;
|
||||
while (j > start && temp < ptr[j - 1]) {
|
||||
ptr[j] = ptr[j - 1];
|
||||
j--;
|
||||
}
|
||||
// for (j = i; j > start && temp < ptr[j - 1]; --j) {
|
||||
// ptr[j] = ptr[j - 1];
|
||||
// }
|
||||
|
||||
ptr[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform merge of data in a window
|
||||
*
|
||||
* @tparam T array data type
|
||||
* @tparam N length of array
|
||||
* @param A pointer to array to sort
|
||||
* @param min start index of window
|
||||
* @param max end index of window
|
||||
* @param mid mid-point of window
|
||||
*/
|
||||
template <typename T, size_t N>
|
||||
static void merge(std::array<T, N> *array, size_t min, size_t max, size_t mid) {
|
||||
size_t firstIndex = min;
|
||||
size_t secondIndex = mid + 1;
|
||||
|
||||
auto ptr = array->data();
|
||||
std::array<T, N + 1> tempArray{0};
|
||||
|
||||
// While there are elements in the left or right runs
|
||||
for (size_t index = min; index <= max; index++) {
|
||||
// If left run head exists and is <= existing right run head.
|
||||
if (firstIndex <= mid &&
|
||||
(secondIndex > max || ptr[firstIndex] <= ptr[secondIndex])) {
|
||||
tempArray[index] = ptr[firstIndex];
|
||||
firstIndex++;
|
||||
} else {
|
||||
tempArray[index] = ptr[secondIndex];
|
||||
secondIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// transfer to the initial array
|
||||
memcpy(ptr + min, tempArray.data() + min, (max - min) * sizeof(T));
|
||||
// for (int index = min; index <= max; index++) ptr[index] =
|
||||
// tempArray[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Final combined algorithm.
|
||||
* Algorithm utilizes ::sorting::merge_insertion::InsertionSort if window length
|
||||
* is less than threshold, else performs merge sort recursively using
|
||||
* ::sorting::merge_insertion::mergeSort
|
||||
*
|
||||
* @tparam T array data type
|
||||
* @tparam N length of array
|
||||
* @param A pointer to array to sort
|
||||
* @param min start index of sort window
|
||||
* @param max end index of sort window
|
||||
* @param threshold window length threshold
|
||||
*/
|
||||
template <typename T, size_t N>
|
||||
void mergeSort(std::array<T, N> *array, size_t min, size_t max,
|
||||
size_t threshold) {
|
||||
// prerequisite
|
||||
if ((max - min) <= threshold) {
|
||||
InsertionSort(array, min, max);
|
||||
} else {
|
||||
// get the middle point
|
||||
size_t mid = (max + min) >> 1;
|
||||
|
||||
// apply merge sort to both parts of this
|
||||
mergeSort(array, min, mid, threshold);
|
||||
mergeSort(array, mid, max, threshold);
|
||||
|
||||
// and finally merge all that sorted stuff
|
||||
merge(array, min, max, mid);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace merge_insertion
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Function to test code using random arrays
|
||||
* @returns none
|
||||
*/
|
||||
static void test() {
|
||||
constexpr size_t size = 30;
|
||||
std::array<int, size> array{0};
|
||||
// input
|
||||
for (int i = 0; i < size; i++) {
|
||||
array[i] = std::rand() % 100 - 50;
|
||||
std::cout << array[i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
sorting::merge_insertion::InsertionSort(&array, 0, size);
|
||||
// sorting::merge_insertion::mergeSort(&array, 0, size, 10);
|
||||
|
||||
// output
|
||||
for (int i = 0; i < size; ++i) {
|
||||
std::cout << array[i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
assert(std::is_sorted(std::begin(array), std::end(array)));
|
||||
std::cout << "Test passed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @return 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
std::srand(std::time(nullptr));
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* \addtogroup sorting Sorting Algorithms
|
||||
* @{
|
||||
* \file
|
||||
* \brief [Merge Sort Algorithm
|
||||
* (MERGE SORT)](https://en.wikipedia.org/wiki/Merge_sort) implementation
|
||||
*
|
||||
* \author [Ayaan Khan](http://github.com/ayaankhan98)
|
||||
*
|
||||
* \details
|
||||
* Merge Sort is an efficient, general purpose, comparison
|
||||
* based sorting algorithm.
|
||||
* Merge Sort is a divide and conquer algorithm
|
||||
* Time Complexity: O(n log n)
|
||||
* It is same for all best case, worst case or average case
|
||||
* Merge Sort is very efficient when for the small data.
|
||||
* In built-in sort function merge sort along with quick sort is used.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
*
|
||||
* The merge() function is used for merging two halves.
|
||||
* The merge(arr, l, m, r) is key process that assumes that
|
||||
* arr[l..m] and arr[m+1..r] are sorted and merges the two
|
||||
* sorted sub-arrays into one.
|
||||
*
|
||||
* @param arr - array with two halves arr[l...m] and arr[m+1...r]
|
||||
* @param l - left index or start index of first half array
|
||||
* @param m - right index or end index of first half array
|
||||
*
|
||||
* (The second array starts form m+1 and goes till r)
|
||||
*
|
||||
* @param r - end index or right index of second half array
|
||||
*/
|
||||
void merge(int *arr, int l, int m, int r) {
|
||||
int n1 = m - l + 1;
|
||||
int n2 = r - m;
|
||||
|
||||
std::vector<int> L(n1), R(n2);
|
||||
|
||||
for (int i = 0; i < n1; i++) L[i] = arr[l + i];
|
||||
for (int j = 0; j < n2; j++) R[j] = arr[m + 1 + j];
|
||||
|
||||
int i = 0, j = 0, k = l;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge sort is a divide and conquer algorithm, it divides the
|
||||
* input array into two halves and calls itself for the two halves
|
||||
* and then calls merge() to merge the two halves
|
||||
*
|
||||
* @param arr - array to be sorted
|
||||
* @param l - left index or start index of array
|
||||
* @param r - right index or end index of array
|
||||
*
|
||||
*/
|
||||
void mergeSort(int *arr, int l, int r) {
|
||||
if (l < r) {
|
||||
int m = l + (r - l) / 2;
|
||||
mergeSort(arr, l, m);
|
||||
mergeSort(arr, m + 1, r);
|
||||
merge(arr, l, m, r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function used to print the array after
|
||||
* sorting
|
||||
*/
|
||||
void show(int *arr, int size) {
|
||||
for (int i = 0; i < size; i++) std::cout << arr[i] << " ";
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
int size;
|
||||
std::cout << "Enter the number of elements: ";
|
||||
std::cin >> size;
|
||||
|
||||
if (size <= 0) {
|
||||
std::cout << "Invalid size.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
int *arr = new int[size];
|
||||
std::cout << "Enter the unsorted elements: ";
|
||||
for (int i = 0; i < size; ++i) {
|
||||
std::cin >> arr[i];
|
||||
}
|
||||
|
||||
mergeSort(arr, 0, size - 1);
|
||||
std::cout << "Sorted array: ";
|
||||
show(arr, size);
|
||||
delete[] arr;
|
||||
return 0;
|
||||
}
|
||||
/** @} */
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Copyright 2020 @author Albirair
|
||||
* @file
|
||||
*
|
||||
* A generic implementation of non-recursive merge sort.
|
||||
*/
|
||||
#include <cstddef> // for size_t
|
||||
#include <iostream>
|
||||
#include <utility> // for std::move & std::remove_reference_t
|
||||
|
||||
namespace sorting {
|
||||
template <class Iterator>
|
||||
void merge(Iterator, Iterator, const Iterator, char[]);
|
||||
/// bottom-up merge sort which sorts elements in a non-decreasing order
|
||||
/**
|
||||
* sorts elements non-recursively by breaking them into small segments,
|
||||
* merging adjacent segments into larger sorted segments, then increasing
|
||||
* the sizes of segments by factors of 2 and repeating the same process.
|
||||
* best-case = worst-case = O(n log(n))
|
||||
* @param first points to the first element
|
||||
* @param last points to 1-step past the last element
|
||||
* @param n the number of elements
|
||||
*/
|
||||
template <class Iterator>
|
||||
void non_recursive_merge_sort(const Iterator first, const Iterator last,
|
||||
const size_t n) {
|
||||
// create a buffer large enough to store all elements
|
||||
// dynamically allocated to comply with cpplint
|
||||
char* buffer = new char[n * sizeof(*first)];
|
||||
// buffer size can be optimized to largest power of 2 less than n
|
||||
// elements divide the container into equally-sized segments whose
|
||||
// length start at 1 and keeps increasing by factors of 2
|
||||
for (size_t length(1); length < n; length <<= 1) {
|
||||
// merge adjacent segments whose number is n / (length * 2)
|
||||
Iterator left(first);
|
||||
for (size_t counter(n / (length << 1)); counter; --counter) {
|
||||
Iterator right(left + length), end(right + length);
|
||||
merge(left, right, end, buffer);
|
||||
left = end;
|
||||
}
|
||||
// if the number of remaining elements (n * 2 % length) is longer
|
||||
// than a segment, merge the remaining elements
|
||||
if ((n & ((length << 1) - 1)) > length)
|
||||
merge(left, left + length, last, buffer);
|
||||
}
|
||||
delete[] buffer;
|
||||
}
|
||||
/// merges 2 sorted adjacent segments into a larger sorted segment
|
||||
/**
|
||||
* best-case = worst-case = O(n)
|
||||
* @param l points to the left part
|
||||
* @param r points to the right part, end of left part
|
||||
* @param e points to end of right part
|
||||
* @param b points at the buffer
|
||||
*/
|
||||
template <class Iterator>
|
||||
void merge(Iterator l, Iterator r, const Iterator e, char b[]) {
|
||||
// create 2 pointers to point at the buffer
|
||||
auto p(reinterpret_cast<std::remove_reference_t<decltype(*l)>*>(b)), c(p);
|
||||
// move the left part of the segment
|
||||
for (Iterator t(l); r != t; ++t) *p++ = std::move(*t);
|
||||
// while neither the buffer nor the right part has been exhausted
|
||||
// move the smallest element of the two back to the container
|
||||
while (e != r && c != p) *l++ = std::move(*r < *c ? *r++ : *c++);
|
||||
// notice only one of the two following loops will be executed
|
||||
// while the right part hasn't bee exhausted, move it back
|
||||
while (e != r) *l++ = std::move(*r++);
|
||||
// while the buffer hasn't bee exhausted, move it back
|
||||
while (c != p) *l++ = std::move(*c++);
|
||||
}
|
||||
/// bottom-up merge sort which sorts elements in a non-decreasing order
|
||||
/**
|
||||
* @param first points to the first element
|
||||
* @param n the number of elements
|
||||
*/
|
||||
template <class Iterator>
|
||||
void non_recursive_merge_sort(const Iterator first, const size_t n) {
|
||||
non_recursive_merge_sort(first, first + n, n);
|
||||
}
|
||||
/// bottom-up merge sort which sorts elements in a non-decreasing order
|
||||
/**
|
||||
* @param first points to the first element
|
||||
* @param last points to 1-step past the last element
|
||||
*/
|
||||
template <class Iterator>
|
||||
void non_recursive_merge_sort(const Iterator first, const Iterator last) {
|
||||
non_recursive_merge_sort(first, last, last - first);
|
||||
}
|
||||
|
||||
} // namespace sorting
|
||||
|
||||
using sorting::non_recursive_merge_sort;
|
||||
|
||||
int main() {
|
||||
int size;
|
||||
std::cout << "Enter the number of elements : ";
|
||||
std::cin >> size;
|
||||
int* arr = new int[size];
|
||||
for (int i = 0; i < size; ++i) {
|
||||
std::cout << "arr[" << i << "] = ";
|
||||
std::cin >> arr[i];
|
||||
}
|
||||
non_recursive_merge_sort(arr, size);
|
||||
std::cout << "Sorted array\n";
|
||||
for (int i = 0; i < size; ++i)
|
||||
std::cout << "arr[" << i << "] = " << arr[i] << '\n';
|
||||
delete[] arr;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Using general algorithms to sort a collection of strings results in
|
||||
// alphanumeric sort. If it is a numeric string, it leads to unnatural sorting
|
||||
|
||||
// eg, an array of strings 1,10,100,2,20,200,3,30,300
|
||||
// would be sorted in that same order by using conventional sorting,
|
||||
// even though we know the correct sorting order is 1,2,3,10,20,30,100,200,300
|
||||
|
||||
// This Programme uses a comparator to sort the array in Numerical order instead
|
||||
// of Alphanumeric order
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
bool NumericSort(std::string a, std::string b) {
|
||||
while (a[0] == '0') {
|
||||
a.erase(a.begin());
|
||||
}
|
||||
while (b[0] == '0') {
|
||||
b.erase(b.begin());
|
||||
}
|
||||
int n = a.length();
|
||||
int m = b.length();
|
||||
if (n == m)
|
||||
return a < b;
|
||||
return n < m;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
std::cout << "Enter number of elements to be sorted Numerically\n";
|
||||
std::cin >> n;
|
||||
|
||||
std::vector<std::string> v(n);
|
||||
std::cout << "Enter the string of Numbers\n";
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::cin >> v[i];
|
||||
}
|
||||
|
||||
sort(v.begin(), v.end());
|
||||
std::cout << "Elements sorted normally \n";
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::cout << v[i] << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
|
||||
std::sort(v.begin(), v.end(), NumericSort);
|
||||
std::cout << "Elements sorted Numerically \n";
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::cout << v[i] << " ";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* C++ implementation Odd Even Sort */
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void oddEven(vector<int> &arr, int size) {
|
||||
bool sorted = false;
|
||||
while (!sorted) {
|
||||
sorted = true;
|
||||
for (int i = 1; i < size - 1; i += 2) // Odd
|
||||
{
|
||||
if (arr[i] > arr[i + 1]) {
|
||||
swap(arr[i], arr[i + 1]);
|
||||
sorted = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < size - 1; i += 2) // Even
|
||||
{
|
||||
if (arr[i] > arr[i + 1]) {
|
||||
swap(arr[i], arr[i + 1]);
|
||||
sorted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void show(vector<int> A, int size) {
|
||||
int i;
|
||||
for (i = 0; i < size; i++) cout << A[i] << "\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
int size, temp;
|
||||
cout << "\nEnter the number of elements : ";
|
||||
cin >> size;
|
||||
|
||||
vector<int> arr;
|
||||
|
||||
cout << "\nEnter the unsorted elements : \n";
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
cin >> temp;
|
||||
arr.push_back(temp);
|
||||
}
|
||||
|
||||
oddEven(arr, size);
|
||||
|
||||
cout << "Sorted array\n";
|
||||
show(arr, size);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief pancake sort sorts a disordered stack of pancakes by flipping any
|
||||
* number of pancakes using a spatula using minimum number of flips.
|
||||
*
|
||||
* @details
|
||||
* Unlike a traditional sorting algorithm, which attempts to sort with the
|
||||
* fewest comparisons possible, the goal is to sort the sequence in as few
|
||||
* reversals as possible. Overall time complexity of pancake sort is O(n^2) For
|
||||
* example: example 1:- Disordered pancake sizes: {2,5,3,7,8} Sorted:
|
||||
* {2,3,5,7,8} For example: example 2:- Disordered pancake sizes:
|
||||
* {22,51,37,73,81} Sorted: {22,37,51,73,81}
|
||||
* @author [Divyansh Gupta](https://github.com/divyansh12323)
|
||||
* @see more on [Pancake sort](https://en.wikipedia.org/wiki/Pancake_sorting)
|
||||
* @see related problem at
|
||||
* [Leetcode](https://leetcode.com/problems/pancake-sorting/)
|
||||
*/
|
||||
|
||||
#include <algorithm> // for std::is_sorted
|
||||
#include <cassert> // for std::assert
|
||||
#include <iostream> // for io operations
|
||||
#include <vector> // for std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace pancake_sort
|
||||
* @brief Functions for [Pancake
|
||||
* sort](https://en.wikipedia.org/wiki/Pancake_sorting) algorithm
|
||||
*/
|
||||
namespace pancake_sort {
|
||||
/**
|
||||
* @brief This implementation is for reversing elements in a a C-style array .
|
||||
* @param [start,end] arr our vector of elements.
|
||||
* @param start starting index of array
|
||||
* @param end ending index of array
|
||||
* @returns void
|
||||
*/
|
||||
template <typename T>
|
||||
void reverse(std::vector<T> &arr, int start, int end) {
|
||||
T temp; // Temporary variable
|
||||
while (start <= end) {
|
||||
temp = arr[start];
|
||||
arr[start] = arr[end];
|
||||
arr[end] = temp;
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief This implementation is for a C-style array input that gets modified in
|
||||
* place.
|
||||
* @param [start,end] arr our vector of elements.
|
||||
* @param size size of given array
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
template <typename T>
|
||||
int pancakeSort(std::vector<T> &arr, int size) {
|
||||
for (int i = size; i > 1; --i) {
|
||||
int max_index = 0, j = 0; // intialize some variables.
|
||||
T max_value = 0;
|
||||
for (j = 0; j < i; j++) {
|
||||
if (arr[j] >= max_value) {
|
||||
max_value = arr[j];
|
||||
max_index = j;
|
||||
}
|
||||
}
|
||||
if (max_index != i - 1) // check for reversing
|
||||
{
|
||||
reverse(arr, 0, max_index);
|
||||
reverse(arr, 0, i - 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace pancake_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// example 1: vector of int
|
||||
const int size1 = 7;
|
||||
std::cout << "\nTest 1- as std::vector<int>...";
|
||||
std::vector<int> arr1 = {23, 10, 20, 11, 12, 6, 7};
|
||||
sorting::pancake_sort::pancakeSort(arr1, size1);
|
||||
assert(std::is_sorted(arr1.begin(), arr1.end()));
|
||||
std::cout << "Passed\n";
|
||||
for (int i = 0; i < size1; i++) {
|
||||
std::cout << arr1[i] << " ,";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// example 2: vector of double
|
||||
const int size2 = 8;
|
||||
std::cout << "\nTest 2- as std::vector<double>...";
|
||||
std::vector<double> arr2 = {23.56, 10.62, 200.78, 111.484,
|
||||
3.9, 1.2, 61.77, 79.6};
|
||||
sorting::pancake_sort::pancakeSort(arr2, size2);
|
||||
assert(std::is_sorted(arr2.begin(), arr2.end()));
|
||||
std::cout << "Passed\n";
|
||||
for (int i = 0; i < size2; i++) {
|
||||
std::cout << arr2[i] << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// example 3:vector of float
|
||||
const int size3 = 7;
|
||||
std::cout << "\nTest 3- as std::vector<float>...";
|
||||
std::vector<float> arr3 = {6.56, 12.62, 200.78, 768.484, 19.27, 68.87, 9.6};
|
||||
sorting::pancake_sort::pancakeSort(arr3, size3);
|
||||
assert(std::is_sorted(arr3.begin(), arr3.end()));
|
||||
std::cout << "Passed\n";
|
||||
for (int i = 0; i < size3; i++) {
|
||||
std::cout << arr3[i] << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Pigeonhole Sort algorithm]
|
||||
* (https://en.wikipedia.org/wiki/Pigeonhole_sort)
|
||||
* @author [Lownish](https://github.com/Lownish)
|
||||
* @details
|
||||
* Pigeonhole sorting is a sorting algorithm that is suitable for sorting lists
|
||||
* of elements where the number of elements and the number of possible key
|
||||
* values are approximately the same. It requires O(n + Range) time where n is
|
||||
* number of elements in input array and ‘Range’ is number of possible values in
|
||||
* array.
|
||||
*
|
||||
* The time Complexity of the algorithm is \f$O(n+N)\f$.
|
||||
*/
|
||||
|
||||
#include <algorithm> //for std::is_sorted
|
||||
#include <array> //for std::array
|
||||
#include <cassert> //for assert
|
||||
#include <iostream> //for io operations
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
|
||||
/**
|
||||
* Pigeonhole sorting of array of size n
|
||||
* The function will sort the array through Pigeonhole algorithm and print
|
||||
* @param arr unsorted array of elements
|
||||
* @returns sorted array of elements
|
||||
*/
|
||||
template <std::size_t N>
|
||||
std::array<int, N> pigeonSort(std::array<int, N> arr) {
|
||||
// Finding min and max*
|
||||
auto min = std::min_element(std::begin(arr), std::end(arr));
|
||||
auto max = std::max_element(std::begin(arr), std::end(arr));
|
||||
|
||||
// Range refers to the number of holes required
|
||||
int range = *max - *min + 1;
|
||||
int *hole = new int[range]();
|
||||
|
||||
// Copying all array values to pigeonhole
|
||||
for (int i = 0; i < N; i++) {
|
||||
hole[arr[i] - *min] = arr[i];
|
||||
}
|
||||
|
||||
// Deleting elements from list and storing to original array
|
||||
int count = 0;
|
||||
for (int i = 0; i < range; i++) {
|
||||
while (hole[i] != '\0') {
|
||||
arr[count] = hole[i];
|
||||
hole[i] = {};
|
||||
count++;
|
||||
}
|
||||
}
|
||||
delete[] hole;
|
||||
|
||||
return arr;
|
||||
}
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* Test function 1 with unsorted array
|
||||
* {8, 3, 2, 7, 4, 6, 8}
|
||||
* @returns none
|
||||
*/
|
||||
static void test_1() {
|
||||
const int n = 7;
|
||||
std::array<int, n> test_array = {8, 3, 2, 7, 4, 6, 8};
|
||||
|
||||
test_array = sorting::pigeonSort<n>(test_array);
|
||||
|
||||
assert(std::is_sorted(std::begin(test_array), std::end(test_array)));
|
||||
|
||||
// Printing sorted array
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::cout << test_array.at(i) << " ";
|
||||
}
|
||||
std::cout << "\nPassed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test function 2 with unsorted array
|
||||
* {802, 630, 20, 745, 52, 300, 612, 932, 78, 187}
|
||||
* @returns none
|
||||
*/
|
||||
static void test_2() {
|
||||
const int n = 10;
|
||||
std::array<int, n> test_array = {802, 630, 20, 745, 52,
|
||||
300, 612, 932, 78, 187};
|
||||
|
||||
test_array = sorting::pigeonSort<n>(test_array);
|
||||
|
||||
assert(std::is_sorted(std::begin(test_array), std::end(test_array)));
|
||||
|
||||
// Printing sorted array
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::cout << test_array.at(i) << " ";
|
||||
}
|
||||
std::cout << "\nPassed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test function 1 with unsorted array
|
||||
* {11,13,12,14}
|
||||
* @returns none
|
||||
*/
|
||||
static void test_3() {
|
||||
const int n = 4;
|
||||
std::array<int, n> test_array = {11, 13, 12, 14};
|
||||
|
||||
test_array = sorting::pigeonSort<n>(test_array);
|
||||
|
||||
assert(std::is_sorted(std::begin(test_array), std::end(test_array)));
|
||||
|
||||
// Printing sorted array
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::cout << test_array.at(i) << " ";
|
||||
}
|
||||
std::cout << "\nPassed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
int main() {
|
||||
test_1();
|
||||
test_2();
|
||||
test_3();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* @file
|
||||
* @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)
|
||||
* 3. Pick a random element as pivot
|
||||
* 4. Pick median as pivot
|
||||
*
|
||||
* The key process in quickSort is partition(). Target of partition is,
|
||||
* given an array and an element x(say) of array as pivot, put x at it's
|
||||
* correct position in sorted array and put all smaller elements (samller
|
||||
* 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 <algorithm> /// for std::is_sorted
|
||||
#include <cassert> /// for std::assert
|
||||
#include <cstdint>
|
||||
#include <ctime> /// for std::time
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @brief Sorting algorithms
|
||||
* @namespace sorting
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace quick_sort
|
||||
* @brief Functions for the [Quick sort
|
||||
* implementation](https://en.wikipedia.org/wiki/Quicksort) in C++
|
||||
*/
|
||||
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
|
||||
*
|
||||
* ### Time Complexity
|
||||
* best case, average Case: O(nlog(n))
|
||||
* Worst Case: O(n^2) (Worst case occur when the partition
|
||||
* is consistently unbalanced.)
|
||||
|
||||
* ### Space Complexity
|
||||
* average Case: O(log(n))
|
||||
* Worst Case: O(n)
|
||||
* It's space complexity is due to the recursive function calls and partitioning process.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
int partition(std::vector<T> *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) {
|
||||
i++; // increment index of smaller element
|
||||
std::swap((*arr)[i], (*arr)[j]);
|
||||
}
|
||||
}
|
||||
|
||||
std::swap((*arr)[i + 1], (*arr)[high]);
|
||||
return (i + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
template <typename T>
|
||||
void quick_sort(std::vector<T> *arr, const int &low, const int &high) {
|
||||
if (low < high) {
|
||||
int p = partition(arr, low, high);
|
||||
|
||||
quick_sort(arr, low, p - 1);
|
||||
quick_sort(arr, p + 1, high);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 <typename T>
|
||||
std::vector<T> quick_sort(std::vector<T> arr, const int &low, const int &high) {
|
||||
if (low < high) {
|
||||
int p = partition(&arr, low, high);
|
||||
|
||||
quick_sort(&arr, low, p - 1);
|
||||
quick_sort(&arr, p + 1, high);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 <typename T>
|
||||
void show(const std::vector<T> &arr, const int &size) {
|
||||
for (int i = 0; i < size; i++) std::cout << arr[i] << " ";
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
} // namespace quick_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void tests() {
|
||||
// 1st test (normal numbers)
|
||||
std::vector<uint64_t> arr = {5, 3, 8, 12, 14, 16, 28, 96, 2, 5977};
|
||||
std::vector<uint64_t> arr_sorted = sorting::quick_sort::quick_sort(
|
||||
arr, 0, int(std::end(arr) - std::begin(arr)) - 1);
|
||||
|
||||
assert(std::is_sorted(std::begin(arr_sorted), std::end(arr_sorted)));
|
||||
std::cout << "\n1st test: passed!\n";
|
||||
|
||||
// 2nd test (normal and negative numbers)
|
||||
std::vector<int64_t> arr2 = {9, 15, 28, 96, 500, -4, -58,
|
||||
-977, -238, -800, -21, -53, -55};
|
||||
std::vector<int64_t> arr_sorted2 = sorting::quick_sort::quick_sort(
|
||||
arr2, 0, std::end(arr2) - std::begin(arr2));
|
||||
|
||||
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<double> arr3 = {29, 36, 1100, 0, 77, 1,
|
||||
6.7, 8.97, 1.74, 950.10, -329.65};
|
||||
std::vector<double> 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<float> arr4(size);
|
||||
for (uint64_t i = 0; i < size; i++) {
|
||||
arr4[i] = static_cast<float>(std::rand()) /
|
||||
static_cast<float>(RAND_MAX / 999.99 - 0.99) -
|
||||
250;
|
||||
}
|
||||
|
||||
std::vector<float> 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<float> 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);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation Details
|
||||
* @details Quick sort 3 works on Dutch National Flag Algorithm
|
||||
* The major difference between simple quicksort and quick sort 3 comes in the
|
||||
* function partition3 In quick_sort_partition3 we divide the vector/array into
|
||||
* 3 parts. quick sort 3 works faster in some cases as compared to simple
|
||||
* quicksort.
|
||||
* @author immortal-j
|
||||
* @author [Krishna Vedala](https://github/kvedala)
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Operator to print the array.
|
||||
* @param out std::ostream object to write to
|
||||
* @param arr array to write
|
||||
*/
|
||||
template <typename T>
|
||||
std::ostream &operator<<(std::ostream &out, const std::vector<T> &arr) {
|
||||
for (size_t i = 0; i < arr.size(); ++i) {
|
||||
out << arr[i];
|
||||
if (i < arr.size() - 1) {
|
||||
out << ", ";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting Algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
namespace { // using un-named namespace here to prevent partition function
|
||||
// being visible to end-users
|
||||
/** This function partitions `arr[]` in three parts
|
||||
* 1. \f$arr[l\ldots i]\f$ contains all elements smaller than pivot
|
||||
* 2. \f$arr[(i+1)\ldots (j-1)]\f$ contains all occurrences of pivot
|
||||
* 3. \f$arr[j\ldots r]\f$ contains all elements greater than pivot
|
||||
* @tparam T type of data in the vector array
|
||||
* @param [in,out] arr vector array being partitioned
|
||||
* @param [in] low lower limit of window to partition
|
||||
* @param [in] high upper limit of window to partition
|
||||
* @param [out] i updated lower limit of partition
|
||||
* @param [out] j updated upper limit of partition
|
||||
*/
|
||||
template <typename T>
|
||||
void partition3(std::vector<T> *arr, int32_t low, int32_t high, int32_t *i,
|
||||
int32_t *j) {
|
||||
// To handle 2 elements
|
||||
if (high - low <= 1) {
|
||||
if ((*arr)[high] < (*arr)[low]) {
|
||||
std::swap((*arr)[high], (*arr)[low]);
|
||||
}
|
||||
*i = low;
|
||||
*j = high;
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t mid = low;
|
||||
T pivot = (*arr)[high];
|
||||
while (mid <= high) {
|
||||
if ((*arr)[mid] < pivot) {
|
||||
std::swap((*arr)[low++], (*arr)[mid++]);
|
||||
} else if ((*arr)[mid] == pivot) {
|
||||
mid++;
|
||||
} else if ((*arr)[mid] > pivot) {
|
||||
std::swap((*arr)[mid], (*arr)[high--]);
|
||||
}
|
||||
}
|
||||
|
||||
// update i and j
|
||||
*i = low - 1;
|
||||
*j = mid; // or high-1
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/** 3-way partition based quick sort. This function accepts array pointer and
|
||||
* modified the input array.
|
||||
* @tparam T type of data in the vector array
|
||||
* @param [in,out] arr vector array to sort
|
||||
* @param [in] low lower limit of window to partition
|
||||
* @param [in] high upper limit of window to partition
|
||||
*/
|
||||
template <typename T>
|
||||
void quicksort(std::vector<T> *arr, int32_t low, int32_t high) {
|
||||
if (low >= high) { // 1 or 0 elements
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t i = 0, j = 0;
|
||||
|
||||
// i and j are passed as reference
|
||||
partition3(arr, low, high, &i, &j);
|
||||
|
||||
// Recur two halves
|
||||
quicksort(arr, low, i);
|
||||
quicksort(arr, j, high);
|
||||
}
|
||||
|
||||
/** 3-way partition based quick sort. This function accepts array by value and
|
||||
* creates a copy of it. The array copy gets sorted and returned by the
|
||||
* function.
|
||||
* @tparam T type of data in the vector array
|
||||
* @param [in] arr vector array to sort
|
||||
* @param [in] low lower limit of window to partition
|
||||
* @param [in] high upper limit of window to partition
|
||||
* @returns sorted array vector
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<T> quicksort(std::vector<T> arr, int32_t low, int32_t high) {
|
||||
if (low >= high) { // 1 or 0 elements
|
||||
return arr;
|
||||
}
|
||||
|
||||
int32_t i = 0, j = 0;
|
||||
|
||||
// i and j are passed as reference
|
||||
partition3(&arr, low, high, &i, &j);
|
||||
|
||||
// Recur two halves
|
||||
quicksort(&arr, low, i);
|
||||
quicksort(&arr, j, high);
|
||||
|
||||
return arr;
|
||||
}
|
||||
} // namespace sorting
|
||||
|
||||
/** Test function for integer type arrays */
|
||||
static void test_int() {
|
||||
std::cout << "\nTesting integer type arrays\n";
|
||||
|
||||
for (int num_tests = 1; num_tests < 21; num_tests++) {
|
||||
size_t size = std::rand() % 500;
|
||||
std::vector<int> arr(size);
|
||||
for (auto &a : arr) {
|
||||
a = std::rand() % 500 - 250; // random numbers between -250, 249
|
||||
}
|
||||
|
||||
std::cout << "Test " << num_tests << "\t Array size:" << size << "\t ";
|
||||
std::vector<int> sorted = sorting::quicksort(arr, 0, int32_t(size) - 1);
|
||||
if (size < 20) {
|
||||
std::cout << "\t Sorted Array is:\n\t";
|
||||
std::cout << sorted << "\n";
|
||||
}
|
||||
assert(std::is_sorted(std::begin(sorted), std::end(sorted)));
|
||||
std::cout << "\t Passed\n";
|
||||
}
|
||||
}
|
||||
|
||||
/** Test function for double type arrays */
|
||||
static void test_double() {
|
||||
std::cout << "\nTesting Double type arrays\n";
|
||||
for (int num_tests = 1; num_tests < 21; num_tests++) {
|
||||
size_t size = std::rand() % 500;
|
||||
std::vector<double> arr(size);
|
||||
for (auto &a : arr) {
|
||||
a = double(std::rand() % 500) -
|
||||
250.f; // random numbers between -250, 249
|
||||
a /= 100.f; // convert to -2.5 to 2.49
|
||||
}
|
||||
|
||||
std::cout << "Test " << num_tests << "\t Array size:" << size << "\t ";
|
||||
std::vector<double> sorted =
|
||||
sorting::quicksort(arr, 0, int32_t(size) - 1);
|
||||
if (size < 20) {
|
||||
std::cout << "\t Sorted Array is:\n\t";
|
||||
std::cout << sorted << "\n";
|
||||
}
|
||||
assert(std::is_sorted(std::begin(sorted), std::end(sorted)));
|
||||
std::cout << "\t Passed\n";
|
||||
}
|
||||
}
|
||||
|
||||
/** Driver program for above functions */
|
||||
int main() {
|
||||
std::srand(std::time(nullptr));
|
||||
test_int();
|
||||
test_double();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Quick Sort without recursion. This method uses the stack instead.
|
||||
* Both recursive and iterative implementations have O(n log n) best case
|
||||
* and O(n^2) worst case.
|
||||
* @details
|
||||
* https://stackoverflow.com/questions/12553238/quicksort-iterative-or-recursive
|
||||
* https://en.wikipedia.org/wiki/Quicksort
|
||||
* https://www.geeksforgeeks.org/iterative-quick-sort/
|
||||
* @author [Sebe324](https://github.com/sebe324)
|
||||
*/
|
||||
|
||||
#include <iostream> /// for std::cout
|
||||
#include <vector> /// for std::vector
|
||||
#include <stack> /// for std::stack
|
||||
#include <algorithm> /// for std::is_sorted
|
||||
#include <cassert> /// for assert
|
||||
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @brief The partition function sorts the array from
|
||||
* start to end and uses the last element as the pivot.
|
||||
* @param arr the array to be sorted
|
||||
* @param start starting index
|
||||
* @param end ending index
|
||||
* @return int next index of the pivot
|
||||
*/
|
||||
int partition(std::vector<int> &arr, int start, int end)
|
||||
{
|
||||
int pivot = arr[end];
|
||||
int index = start - 1;
|
||||
|
||||
for (int j = start; j < end; j++) {
|
||||
if (arr[j] <= pivot) {
|
||||
std::swap(arr[++index], arr[j]);
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(arr[index + 1], arr[end]);
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The main sorting function
|
||||
* @details The iterative quick sort uses
|
||||
* the stack instead of recursion for saving
|
||||
* and restoring the environment between calls.
|
||||
* It does not need the end and start params, because
|
||||
* it is not recursive.
|
||||
* @param arr array to be sorted
|
||||
* @return void
|
||||
*/
|
||||
void iterativeQuickSort(std::vector<int> &arr)
|
||||
{
|
||||
std::stack<int> stack;
|
||||
int start = 0;
|
||||
int end = arr.size()-1;
|
||||
stack.push(start);
|
||||
stack.push(end);
|
||||
|
||||
while(!stack.empty())
|
||||
{
|
||||
end = stack.top();
|
||||
stack.pop();
|
||||
start = stack.top();
|
||||
stack.pop();
|
||||
|
||||
int pivotIndex = partition(arr,start,end);
|
||||
|
||||
if(pivotIndex -1 > start)
|
||||
{
|
||||
stack.push(start);
|
||||
stack.push(pivotIndex-1);
|
||||
}
|
||||
|
||||
if(pivotIndex+1<end)
|
||||
{
|
||||
stack.push(pivotIndex+1);
|
||||
stack.push(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sorting
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
void tests()
|
||||
{
|
||||
//TEST 1 - Positive numbers
|
||||
std::vector<int> case1={100,534,1000000,553,10,61,2000,238,2756,9,12,56,30};
|
||||
std::cout<<"TEST 1\n";
|
||||
std::cout<<"Before: \n";
|
||||
for(auto x : case1) std::cout<<x<<",";
|
||||
std::cout<<"\n";
|
||||
sorting::iterativeQuickSort(case1);
|
||||
assert(std::is_sorted(std::begin(case1),std::end(case1)));
|
||||
std::cout<<"Test 1 succesful!\n";
|
||||
std::cout<<"After: \n";
|
||||
for(auto x : case1) std::cout<<x<<",";
|
||||
std::cout<<"\n";
|
||||
|
||||
//TEST 2 - Negative numbers
|
||||
std::vector<int> case2={-10,-2,-5,-2,-3746,-785,-123, -452, -32456};
|
||||
std::cout<<"TEST 2\n";
|
||||
std::cout<<"Before: \n";
|
||||
for(auto x : case2) std::cout<<x<<",";
|
||||
std::cout<<"\n";
|
||||
sorting::iterativeQuickSort(case2);
|
||||
assert(std::is_sorted(std::begin(case2),std::end(case2)));
|
||||
std::cout<<"Test 2 succesful!\n";
|
||||
std::cout<<"After: \n";
|
||||
for(auto x : case2) std::cout<<x<<",";
|
||||
std::cout<<"\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
tests(); // run self test implementation
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
void radixsort(int a[], int n) {
|
||||
int count[10];
|
||||
int* output = new int[n];
|
||||
memset(output, 0, n * sizeof(*output));
|
||||
memset(count, 0, sizeof(count));
|
||||
int max = 0;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (a[i] > max) {
|
||||
max = a[i];
|
||||
}
|
||||
}
|
||||
int maxdigits = 0;
|
||||
while (max) {
|
||||
maxdigits++;
|
||||
max /= 10;
|
||||
}
|
||||
for (int j = 0; j < maxdigits; j++) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
int t = std::pow(10, j);
|
||||
count[(a[i] % (10 * t)) / t]++;
|
||||
}
|
||||
int k = 0;
|
||||
for (int p = 0; p < 10; p++) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
int t = std::pow(10, j);
|
||||
if ((a[i] % (10 * t)) / t == p) {
|
||||
output[k] = a[i];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(count, 0, sizeof(count));
|
||||
for (int i = 0; i < n; ++i) {
|
||||
a[i] = output[i];
|
||||
}
|
||||
}
|
||||
delete[] output;
|
||||
}
|
||||
|
||||
void print(int a[], int n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
std::cout << a[i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int a[] = {170, 45, 75, 90, 802, 24, 2, 66};
|
||||
int n = sizeof(a) / sizeof(a[0]);
|
||||
radixsort(a, n);
|
||||
print(a, n);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Algorithm of [Radix sort](https://en.wikipedia.org/wiki/Radix_sort)
|
||||
* @author [Suyash Jaiswal](https://github.com/Suyashjaiswal)
|
||||
* @details
|
||||
* Sort the vector of unsigned integers using radix sort i.e. sorting digit by
|
||||
* digit using [Counting Sort](https://en.wikipedia.org/wiki/Counting_sort) as
|
||||
* subroutine. Running time of radix sort is O(d*(n+b)) where b is the base for
|
||||
* representing numbers and d in the max digits in input integers and n is
|
||||
* number of unsigned integers. consider example for n = 5, aray elements =
|
||||
* 432,234,143,332,123 sorting digit by digit sorting according to 1) 1st digit
|
||||
* place
|
||||
* => 432, 332, 143, 123, 234
|
||||
*
|
||||
* 2) 2nd digit place
|
||||
* => 123, 432, 332, 234, 143
|
||||
*
|
||||
* 3) 3rd digit place
|
||||
* => 123, 143, 234, 332, 432
|
||||
*
|
||||
* using count sort at each step, which is stable.
|
||||
* stable => already sorted according to previous digits.
|
||||
*/
|
||||
|
||||
/// header files
|
||||
|
||||
#include <algorithm> /// for collection of functions
|
||||
#include <cassert> /// for a macro called assert which can be used to verify assumptions
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for io operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace radix_sort
|
||||
* @brief Functions for [Radix sort](https://en.wikipedia.org/wiki/Radix_sort)
|
||||
* algorithm
|
||||
*/
|
||||
namespace radix_sort {
|
||||
/**
|
||||
* @brief Function to sort vector according to current digit using stable
|
||||
* sorting.
|
||||
* @param cur_digit - sort according to the cur_digit
|
||||
* @param ar - vector to be sorted
|
||||
* @returns std::vector sorted till ith digit
|
||||
*/
|
||||
std::vector<uint64_t> step_ith(
|
||||
uint16_t cur_digit,
|
||||
const std::vector<uint64_t>& ar) { // sorting according to current digit.
|
||||
int n = ar.size();
|
||||
std::vector<uint32_t> position(10, 0);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
position[(ar[i] / cur_digit) %
|
||||
10]++; // counting frequency of 0-9 at cur_digit.
|
||||
}
|
||||
int cur = 0;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
int a = position[i];
|
||||
position[i] = cur; // assingning starting position of 0-9.
|
||||
cur += a;
|
||||
}
|
||||
std::vector<uint64_t> temp(n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
temp[position[(ar[i] / cur_digit) % 10]] =
|
||||
ar[i]; // storing ar[i] in ar[i]'s cur_digit expected position of
|
||||
// this step.
|
||||
position[(ar[i] / cur_digit) %
|
||||
10]++; // incrementing ar[i]'s cur_digit position by 1, as
|
||||
// current place used by ar[i].
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
/**
|
||||
* @brief Function to sort vector digit by digit.
|
||||
* @param ar - vector to be sorted
|
||||
* @returns sorted vector
|
||||
*/
|
||||
std::vector<uint64_t> radix(const std::vector<uint64_t>& ar) {
|
||||
uint64_t max_ele =
|
||||
*max_element(ar.begin(), ar.end()); // returns the max element.
|
||||
std::vector<uint64_t> temp = ar;
|
||||
for (int i = 1; max_ele / i > 0;
|
||||
i *= 10) { // loop breaks when i > max_ele because no further digits
|
||||
// left to makes changes in aray.
|
||||
temp = step_ith(i, temp);
|
||||
}
|
||||
for (uint64_t i : temp) {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
return temp;
|
||||
}
|
||||
} // namespace radix_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Function to test the above algorithm
|
||||
* @returns none
|
||||
*/
|
||||
static void tests() {
|
||||
/// Test 1
|
||||
std::vector<uint64_t> ar1 = {432, 234, 143, 332, 123};
|
||||
ar1 = sorting::radix_sort::radix(ar1);
|
||||
assert(std::is_sorted(ar1.begin(), ar1.end()));
|
||||
/// Test 2
|
||||
std::vector<uint64_t> ar2 = {213, 3214, 123, 111, 112, 142,
|
||||
133, 132, 32, 12, 113};
|
||||
ar2 = sorting::radix_sort::radix(ar2);
|
||||
assert(std::is_sorted(ar2.begin(), ar2.end()));
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
tests(); // execute the tests
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Random Pivot Quick
|
||||
* Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation)
|
||||
* algorithm.
|
||||
* @details
|
||||
* * A random pivot quick sort algorithm is pretty much same as quick
|
||||
* sort with a difference of having a logic of selecting next pivot element from
|
||||
* the input array.
|
||||
* * Where in quick sort is fast, but still can give you the time
|
||||
* complexity of O(n^2) in worst case.
|
||||
* * To avoid hitting the time complexity of O(n^2), we use the logic
|
||||
* of randomize the selection process of pivot element.
|
||||
*
|
||||
* ### Logic
|
||||
* * The logic is pretty simple, the only change is in the
|
||||
* partitioning algorithm, which is selecting the pivot element.
|
||||
* * Instead of selecting the last or the first element from array
|
||||
* for pivot we use a random index to select pivot element.
|
||||
* * This avoids hitting the O(n^2) time complexity in practical
|
||||
* use cases.
|
||||
*
|
||||
* ### Partition Logic
|
||||
* * Partitions are done such as numbers lower than the "pivot"
|
||||
* element is arranged on the left side of the "pivot", and number larger than
|
||||
* the "pivot" element are arranged on the right part of the array.
|
||||
*
|
||||
* ### Algorithm
|
||||
* * Select the pivot element randomly using getRandomIndex() function
|
||||
* from this namespace.
|
||||
* * Initialize the pInd (partition index) from the start of the
|
||||
* array.
|
||||
* * Loop through the array from start to less than end. (from start
|
||||
* to < end). (Inside the loop) :-
|
||||
* * Check if the current element (arr[i]) is less than the
|
||||
* pivot element in each iteration.
|
||||
* * If current element in the iteration is less than the
|
||||
* pivot element, then swap the elements at current index (i) and partition
|
||||
* index (pInd) and increment the partition index by one.
|
||||
* * At the end of the loop, swap the pivot element with partition
|
||||
* index element.
|
||||
* * Return the partition index from the function.
|
||||
*
|
||||
* @author [Nitin Sharma](https://github.com/foo290)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::is_sorted(), std::swap()
|
||||
#include <array> /// for std::array
|
||||
#include <cassert> /// for assert
|
||||
#include <ctime> /// for initializing random number generator
|
||||
#include <iostream> /// for IO operations
|
||||
#include <tuple> /// for returning multiple values form a function at once
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @brief Functions for the [Random Pivot Quick
|
||||
* Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation)
|
||||
* implementation
|
||||
* @namespace random_pivot_quick_sort
|
||||
*/
|
||||
namespace random_pivot_quick_sort {
|
||||
/**
|
||||
* @brief Utility function to print the array
|
||||
* @tparam T size of the array
|
||||
* @param arr array used to print its content
|
||||
* @returns void
|
||||
* */
|
||||
template <size_t T>
|
||||
void showArray(std::array<int64_t, T> arr) {
|
||||
for (int64_t i = 0; i < arr.size(); i++) {
|
||||
std::cout << arr[i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Takes the start and end indices of an array and returns a random
|
||||
* int64_teger between the range of those two for selecting pivot element.
|
||||
*
|
||||
* @param start The starting index.
|
||||
* @param end The ending index.
|
||||
* @returns int64_t A random number between start and end index.
|
||||
* */
|
||||
int64_t getRandomIndex(int64_t start, int64_t end) {
|
||||
srand(time(nullptr)); // Initialize random number generator.
|
||||
int64_t randomPivotIndex = start + rand() % (end - start + 1);
|
||||
return randomPivotIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A partition function which handles the partition logic of quick sort.
|
||||
* @tparam size size of the array to be passed as argument.
|
||||
* @param start The start index of the passed array
|
||||
* @param end The ending index of the passed array
|
||||
* @returns std::tuple<int64_t , std::array<int64_t , size>> A tuple of pivot
|
||||
* index and pivot sorted array.
|
||||
*/
|
||||
template <size_t size>
|
||||
std::tuple<int64_t, std::array<int64_t, size>> partition(
|
||||
std::array<int64_t, size> arr, int64_t start, int64_t end) {
|
||||
int64_t pivot = arr[end]; // Randomly selected element will be here from
|
||||
// caller function (quickSortRP()).
|
||||
int64_t pInd = start;
|
||||
|
||||
for (int64_t i = start; i < end; i++) {
|
||||
if (arr[i] <= pivot) {
|
||||
std::swap(arr[i], arr[pInd]); // swapping the elements from current
|
||||
// index to pInd.
|
||||
pInd++;
|
||||
}
|
||||
}
|
||||
std::swap(arr[pInd],
|
||||
arr[end]); // swapping the pivot element to its sorted position
|
||||
return std::make_tuple(pInd, arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Random pivot quick sort function. This function is the starting point
|
||||
* of the algorithm.
|
||||
* @tparam size size of the array to be passed as argument.
|
||||
* @param start The start index of the passed array
|
||||
* @param end The ending index of the passed array
|
||||
* @returns std::array<int64_t , size> A fully sorted array in ascending order.
|
||||
*/
|
||||
template <size_t size>
|
||||
std::array<int64_t, size> quickSortRP(std::array<int64_t, size> arr,
|
||||
int64_t start, int64_t end) {
|
||||
if (start < end) {
|
||||
int64_t randomIndex = getRandomIndex(start, end);
|
||||
|
||||
// switching the pivot with right most bound.
|
||||
std::swap(arr[end], arr[randomIndex]);
|
||||
|
||||
int64_t pivotIndex = 0;
|
||||
// getting pivot index and pivot sorted array.
|
||||
std::tie(pivotIndex, arr) = partition(arr, start, end);
|
||||
|
||||
// Recursively calling
|
||||
std::array<int64_t, arr.size()> rightSortingLeft =
|
||||
quickSortRP(arr, start, pivotIndex - 1);
|
||||
std::array<int64_t, arr.size()> full_sorted =
|
||||
quickSortRP(rightSortingLeft, pivotIndex + 1, end);
|
||||
arr = full_sorted;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A function utility to generate unsorted array of given size and range.
|
||||
* @tparam size Size of the output array.
|
||||
* @param from Stating of the range.
|
||||
* @param to Ending of the range.
|
||||
* @returns std::array<int64_t , size> Unsorted array of specified size.
|
||||
* */
|
||||
template <size_t size>
|
||||
std::array<int64_t, size> generateUnsortedArray(int64_t from, int64_t to) {
|
||||
srand(time(nullptr));
|
||||
std::array<int64_t, size> unsortedArray{};
|
||||
assert(from < to);
|
||||
int64_t i = 0;
|
||||
while (i < size) {
|
||||
int64_t randomNum = from + rand() % (to - from + 1);
|
||||
if (randomNum) {
|
||||
unsortedArray[i] = randomNum;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return unsortedArray;
|
||||
}
|
||||
|
||||
} // namespace random_pivot_quick_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief a class containing the necessary test cases
|
||||
*/
|
||||
class TestCases {
|
||||
private:
|
||||
/**
|
||||
* @brief A function to print64_t given message on console.
|
||||
* @tparam T Type of the given message.
|
||||
* @returns void
|
||||
* */
|
||||
template <typename T>
|
||||
void log(T msg) {
|
||||
// It's just to avoid writing cout and endl
|
||||
std::cout << "[TESTS] : ---> " << msg << std::endl;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Executes test cases
|
||||
* @returns void
|
||||
* */
|
||||
void runTests() {
|
||||
log("Running Tests...");
|
||||
|
||||
testCase_1();
|
||||
testCase_2();
|
||||
testCase_3();
|
||||
|
||||
log("Test Cases over!");
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case with single input
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_1() {
|
||||
const int64_t inputSize = 1;
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
log("This is test case 1 for Random Pivot Quick Sort Algorithm : ");
|
||||
log("Description:");
|
||||
log(" EDGE CASE : Only contains one element");
|
||||
std::array<int64_t, inputSize> unsorted_arr{2};
|
||||
|
||||
int64_t start = 0;
|
||||
int64_t end = unsorted_arr.size() - 1; // length - 1
|
||||
|
||||
log("Running algorithm of data of length 50 ...");
|
||||
std::array<int64_t, unsorted_arr.size()> sorted_arr =
|
||||
sorting::random_pivot_quick_sort::quickSortRP(unsorted_arr, start,
|
||||
end);
|
||||
log("Algorithm finished!");
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(std::is_sorted(sorted_arr.begin(), sorted_arr.end()));
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 1 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case with input array of length 500
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_2() {
|
||||
const int64_t inputSize = 500;
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
log("Description:");
|
||||
log(" BIG INPUT : Contains 500 elements and repeated elements");
|
||||
log("This is test case 2 for Random Pivot Quick Sort Algorithm : ");
|
||||
std::array<int64_t, inputSize> unsorted_arr =
|
||||
sorting::random_pivot_quick_sort::generateUnsortedArray<inputSize>(
|
||||
1, 10000);
|
||||
|
||||
int64_t start = 0;
|
||||
int64_t end = unsorted_arr.size() - 1; // length - 1
|
||||
|
||||
log("Running algorithm of data of length 500 ...");
|
||||
std::array<int64_t, unsorted_arr.size()> sorted_arr =
|
||||
sorting::random_pivot_quick_sort::quickSortRP(unsorted_arr, start,
|
||||
end);
|
||||
log("Algorithm finished!");
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(std::is_sorted(sorted_arr.begin(), sorted_arr.end()));
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 2 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case with array of length 1000.
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_3() {
|
||||
const int64_t inputSize = 1000;
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
log("This is test case 3 for Random Pivot Quick Sort Algorithm : ");
|
||||
log("Description:");
|
||||
log(" LARGE INPUT : Contains 1000 elements and repeated elements");
|
||||
std::array<int64_t, inputSize> unsorted_arr =
|
||||
sorting::random_pivot_quick_sort::generateUnsortedArray<inputSize>(
|
||||
1, 10000);
|
||||
|
||||
int64_t start = 0;
|
||||
int64_t end = unsorted_arr.size() - 1; // length - 1
|
||||
|
||||
log("Running algorithm...");
|
||||
std::array<int64_t, unsorted_arr.size()> sorted_arr =
|
||||
sorting::random_pivot_quick_sort::quickSortRP(unsorted_arr, start,
|
||||
end);
|
||||
log("Algorithm finished!");
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(std::is_sorted(sorted_arr.begin(), sorted_arr.end()));
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 3 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
TestCases tc = TestCases();
|
||||
tc.runTests();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // Executes various test cases.
|
||||
|
||||
const int64_t inputSize = 10;
|
||||
std::array<int64_t, inputSize> unsorted_array =
|
||||
sorting::random_pivot_quick_sort::generateUnsortedArray<inputSize>(
|
||||
50, 1000);
|
||||
std::cout << "Unsorted array is : " << std::endl;
|
||||
sorting::random_pivot_quick_sort::showArray(unsorted_array);
|
||||
|
||||
std::array<int64_t, inputSize> sorted_array =
|
||||
sorting::random_pivot_quick_sort::quickSortRP(
|
||||
unsorted_array, 0, unsorted_array.size() - 1);
|
||||
std::cout << "Sorted array is : " << std::endl;
|
||||
sorting::random_pivot_quick_sort::showArray(sorted_array);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* @file
|
||||
* @author [Aditya Prakash](https://adityaprakash.tech)
|
||||
* @brief This is an implementation of a recursive version of the [Bubble sort
|
||||
algorithm](https://www.geeksforgeeks.org/recursive-bubble-sort/)
|
||||
*
|
||||
* @details
|
||||
* The working principle of the Bubble sort algorithm.
|
||||
|
||||
* Bubble sort is a simple sorting algorithm used to rearrange a set of
|
||||
ascending or descending order elements.
|
||||
* Bubble sort gets its name from the fact that data "bubbles" to the top of the
|
||||
dataset.
|
||||
|
||||
* ### Algorithm
|
||||
|
||||
* What is Swap?
|
||||
|
||||
* Swapping two numbers means that we interchange their values.
|
||||
* Often, an additional variable is required for this operation.
|
||||
* This is further illustrated in the following:
|
||||
|
||||
* void swap(int x, int y){
|
||||
* int z = x;
|
||||
* x = y;
|
||||
* y = z;
|
||||
* }
|
||||
|
||||
* The above process is a typical displacement process.
|
||||
* When we assign a value to x, the old value of x is lost.
|
||||
* That's why we create a temporary variable z to store the initial value of x.
|
||||
* z is further used to assign the initial value of x to y, to complete
|
||||
swapping.
|
||||
|
||||
* Recursion
|
||||
|
||||
* While the recursive method does not necessarily have advantages over
|
||||
iterative
|
||||
* versions, but it is useful to enhance the understanding of the algorithm and
|
||||
* recursion itself. In Recursive Bubble sort algorithm, we firstly call the
|
||||
* function on the entire array, and for every subsequent function call, we
|
||||
exclude
|
||||
* the last element. This fixes the last element for that sub-array.Formally,
|
||||
for
|
||||
* `ith` iteration, we consider elements up to n-i, where n is the number of
|
||||
* elements in the array. Exit condition: n==1; i.e. the sub-array contains only
|
||||
* one element.
|
||||
|
||||
* Complexity
|
||||
* Time complexity: O(n) best case; O(n²) average case; O(n²) worst case
|
||||
* Space complexity: O(n)
|
||||
|
||||
* We need to traverse the array `n * (n-1)` times. However, if the entire array
|
||||
is
|
||||
* already sorted, then we need to traverse it only once. Hence, O(n) is the
|
||||
best case
|
||||
* complexity
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::is_sorted
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of the recursive_bubble_sort. A vector is
|
||||
* passed to the function which is then dereferenced, so that the changes are
|
||||
* reflected in the original vector. It also accepts a second parameter of
|
||||
* type `int` and name `n`, which is the size of the array.
|
||||
*
|
||||
* @tparam T type of data variables in the array
|
||||
* @param nums our array of elements.
|
||||
* @param n size of the array
|
||||
*/
|
||||
template <typename T>
|
||||
void recursive_bubble_sort(std::vector<T> *nums, uint64_t n) {
|
||||
if (n == 1) { //!< base case; when size of the array is 1
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint64_t i = 0; i < n - 1; i++) { //!< iterating over the entire array
|
||||
//!< if a larger number appears before the smaller one, swap them.
|
||||
if ((*nums)[i] > (*nums)[i + 1]) {
|
||||
std::swap((*nums)[i], (*nums)[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
//!< calling the function after we have fixed the last element
|
||||
recursive_bubble_sort(nums, n - 1);
|
||||
}
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st example. Creating an array of type `int`.
|
||||
std::cout << "1st test using `int`\n";
|
||||
const uint64_t size = 6;
|
||||
std::vector<int64_t> arr;
|
||||
// populating the array
|
||||
arr.push_back(22);
|
||||
arr.push_back(46);
|
||||
arr.push_back(94);
|
||||
arr.push_back(12);
|
||||
arr.push_back(37);
|
||||
arr.push_back(63);
|
||||
// array populating ends
|
||||
|
||||
sorting::recursive_bubble_sort(&arr, size);
|
||||
assert(std::is_sorted(std::begin(arr), std::end(arr)));
|
||||
std::cout << " 1st test passed!\n";
|
||||
// printing the array
|
||||
for (uint64_t i = 0; i < size; i++) {
|
||||
std::cout << arr[i] << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// 2nd example. Creating an array of type `double`.
|
||||
std::cout << "2nd test using doubles\n";
|
||||
std::vector<double> double_arr;
|
||||
|
||||
// populating the array
|
||||
double_arr.push_back(20.4);
|
||||
double_arr.push_back(62.7);
|
||||
double_arr.push_back(12.2);
|
||||
double_arr.push_back(43.6);
|
||||
double_arr.push_back(74.1);
|
||||
double_arr.push_back(57.9);
|
||||
// array populating ends
|
||||
|
||||
sorting::recursive_bubble_sort(&double_arr, size);
|
||||
assert(std::is_sorted(std::begin(double_arr), std::end(double_arr)));
|
||||
std::cout << " 2nd test passed!\n";
|
||||
// printing the array
|
||||
for (uint64_t i = 0; i < size; i++) {
|
||||
std::cout << double_arr[i] << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/******************************************************************************
|
||||
* @file
|
||||
* @brief Implementation of the [Selection
|
||||
* sort](https://en.wikipedia.org/wiki/Selection_sort) implementation using
|
||||
* swapping
|
||||
* @details
|
||||
* The selection sort algorithm divides the input vector into two parts: a
|
||||
* sorted subvector of items which is built up from left to right at the front
|
||||
* (left) of the vector, and a subvector of the remaining unsorted items that
|
||||
* occupy the rest of the vector. Initially, the sorted subvector is empty, and
|
||||
* the unsorted subvector is the entire input vector. The algorithm proceeds by
|
||||
* finding the smallest (or largest, depending on the sorting order) element in
|
||||
* the unsorted subvector, exchanging (swapping) it with the leftmost unsorted
|
||||
* element (putting it in sorted order), and moving the subvector boundaries one
|
||||
* element to the right.
|
||||
*
|
||||
* ### Implementation
|
||||
*
|
||||
* SelectionSort
|
||||
* The algorithm divides the input vector into two parts: the subvector of items
|
||||
* already sorted, which is built up from left to right. Initially, the sorted
|
||||
* subvector is empty and the unsorted subvector is the entire input vector. The
|
||||
* algorithm proceeds by finding the smallest element in the unsorted subvector,
|
||||
* exchanging (swapping) it with the leftmost unsorted element (putting it in
|
||||
* sorted order), and moving the subvector boundaries one element to the right.
|
||||
*
|
||||
* @author [Lajat Manekar](https://github.com/Lazeeez)
|
||||
* @author Unknown author
|
||||
*******************************************************************************/
|
||||
#include <algorithm> /// for std::is_sorted
|
||||
#include <cassert> /// for std::assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/******************************************************************************
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*******************************************************************************/
|
||||
namespace sorting {
|
||||
/******************************************************************************
|
||||
* @brief The main function which implements Selection sort
|
||||
* @param arr vector to be sorted
|
||||
* @param len length of vector to be sorted
|
||||
* @returns @param array resultant sorted vector
|
||||
*******************************************************************************/
|
||||
|
||||
std::vector<uint64_t> selectionSort(const std::vector<uint64_t> &arr,
|
||||
uint64_t len) {
|
||||
std::vector<uint64_t> array(
|
||||
arr.begin(),
|
||||
arr.end()); // declare a vector in which result will be stored
|
||||
for (uint64_t it = 0; it < len; ++it) {
|
||||
uint64_t min = it; // set min value
|
||||
for (uint64_t it2 = it + 1; it2 < len; ++it2) {
|
||||
if (array[it2] < array[min]) { // check which element is smaller
|
||||
min = it2; // store index of smallest element to min
|
||||
}
|
||||
}
|
||||
|
||||
if (min != it) { // swap if min does not match to i
|
||||
uint64_t tmp = array[min];
|
||||
array[min] = array[it];
|
||||
array[it] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return array; // return sorted vector
|
||||
}
|
||||
} // namespace sorting
|
||||
|
||||
/*******************************************************************************
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*******************************************************************************/
|
||||
static void test() {
|
||||
// testcase #1
|
||||
// [1, 0, 0, 1, 1, 0, 2, 1] returns [0, 0, 0, 1, 1, 1, 1, 2]
|
||||
std::vector<uint64_t> vector1 = {1, 0, 0, 1, 1, 0, 2, 1};
|
||||
uint64_t vector1size = vector1.size();
|
||||
std::cout << "1st test... ";
|
||||
std::vector<uint64_t> result_test1;
|
||||
result_test1 = sorting::selectionSort(vector1, vector1size);
|
||||
assert(std::is_sorted(result_test1.begin(), result_test1.end()));
|
||||
std::cout << "Passed" << std::endl;
|
||||
|
||||
// testcase #2
|
||||
// [19, 22, 540, 241, 156, 140, 12, 1] returns [1, 12, 19, 22, 140, 156,
|
||||
// 241,540]
|
||||
std::vector<uint64_t> vector2 = {19, 22, 540, 241, 156, 140, 12, 1};
|
||||
uint64_t vector2size = vector2.size();
|
||||
std::cout << "2nd test... ";
|
||||
std::vector<uint64_t> result_test2;
|
||||
result_test2 = sorting::selectionSort(vector2, vector2size);
|
||||
assert(std::is_sorted(result_test2.begin(), result_test2.end()));
|
||||
std::cout << "Passed" << std::endl;
|
||||
|
||||
// testcase #3
|
||||
// [11, 20, 30, 41, 15, 60, 82, 15] returns [11, 15, 15, 20, 30, 41, 60, 82]
|
||||
std::vector<uint64_t> vector3 = {11, 20, 30, 41, 15, 60, 82, 15};
|
||||
uint64_t vector3size = vector3.size();
|
||||
std::cout << "3rd test... ";
|
||||
std::vector<uint64_t> result_test3;
|
||||
result_test3 = sorting::selectionSort(vector3, vector3size);
|
||||
assert(std::is_sorted(result_test3.begin(), result_test3.end()));
|
||||
std::cout << "Passed" << std::endl;
|
||||
|
||||
// testcase #4
|
||||
// [1, 9, 11, 546, 26, 65, 212, 14, -11] returns [-11, 1, 9, 11, 14, 26, 65,
|
||||
// 212, 546]
|
||||
std::vector<uint64_t> vector4 = {1, 9, 11, 546, 26, 65, 212, 14};
|
||||
uint64_t vector4size = vector2.size();
|
||||
std::cout << "4th test... ";
|
||||
std::vector<uint64_t> result_test4;
|
||||
result_test4 = sorting::selectionSort(vector4, vector4size);
|
||||
assert(std::is_sorted(result_test4.begin(), result_test4.end()));
|
||||
std::cout << "Passed" << std::endl;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*******************************************************************************/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Selection
|
||||
* sort](https://en.wikipedia.org/wiki/Selection_sort)
|
||||
* implementation using recursion
|
||||
* @details
|
||||
* The selection sort algorithm divides the input list into two parts: a sorted
|
||||
* sublist of items which is built up from left to right at the front (left) of
|
||||
* the list, and a sublist of the remaining unsorted items that occupy the rest
|
||||
* of the list. Initially, the sorted sublist is empty, and the unsorted sublist
|
||||
* is the entire input list. The algorithm proceeds by finding the smallest (or
|
||||
* largest, depending on the sorting order) element in the unsorted sublist,
|
||||
* exchanging (swapping) it with the leftmost unsorted element (putting it in
|
||||
* sorted order), and moving the sublist boundaries one element to the right.
|
||||
*
|
||||
* ### Implementation
|
||||
* FindMinIndex
|
||||
* This function finds the minimum element of the array(list) recursively by
|
||||
* simply comparing the minimum element of array reduced size by 1 and compares
|
||||
* it to the last element of the array to find the minimum of the whole array.
|
||||
*
|
||||
* SelectionSortRecursive
|
||||
* Just like selection sort, it divides the list into two parts (i.e.: sorted
|
||||
* and unsorted) and finds the minimum of the unsorted array. By calling the
|
||||
* `FindMinIndex` function, it swaps the minimum element with the first element
|
||||
* of the list, and then solves recursively for the remaining unsorted list.
|
||||
* @author [Tushar Khanduri](https://github.com/Tushar-K24)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::is_sorted
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for std::swap and io operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace selection_sort_recursive
|
||||
* @brief Functions for the [Selection
|
||||
* sort](https://en.wikipedia.org/wiki/Selection_sort)
|
||||
* implementation using recursion
|
||||
*/
|
||||
namespace selection_sort_recursive {
|
||||
/**
|
||||
* @brief The main function finds the index of the minimum element
|
||||
* @tparam T type of array
|
||||
* @param in_arr array whose minimum element is to be returned
|
||||
* @param current_position position/index from where the in_arr starts
|
||||
* @returns index of the minimum element
|
||||
*/
|
||||
template <typename T>
|
||||
uint64_t findMinIndex(const std::vector<T> &in_arr,
|
||||
uint64_t current_position = 0) {
|
||||
if (current_position + 1 == in_arr.size()) {
|
||||
return current_position;
|
||||
}
|
||||
uint64_t answer = findMinIndex(in_arr, current_position + 1);
|
||||
if (in_arr[current_position] < in_arr[answer]) {
|
||||
answer = current_position;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The main function implements Selection sort
|
||||
* @tparam T type of array
|
||||
* @param in_arr array to be sorted,
|
||||
* @param current_position position/index from where the in_arr starts
|
||||
* @returns void
|
||||
*/
|
||||
template <typename T>
|
||||
void selectionSortRecursive(std::vector<T> &in_arr,
|
||||
uint64_t current_position = 0) {
|
||||
if (current_position == in_arr.size()) {
|
||||
return;
|
||||
}
|
||||
uint64_t min_element_idx =
|
||||
selection_sort_recursive::findMinIndex(in_arr, current_position);
|
||||
if (min_element_idx != current_position) {
|
||||
std::swap(in_arr[min_element_idx], in_arr[current_position]);
|
||||
}
|
||||
selectionSortRecursive(in_arr, current_position + 1);
|
||||
}
|
||||
} // namespace selection_sort_recursive
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
// [1, 0, 2, 1] return [0, 1, 1, 2]
|
||||
std::vector<uint64_t> array1 = {0, 1, 1, 2};
|
||||
std::cout << "1st test... ";
|
||||
sorting::selection_sort_recursive::selectionSortRecursive(array1);
|
||||
assert(std::is_sorted(std::begin(array1), std::end(array1)));
|
||||
std::cout << "passed" << std::endl;
|
||||
// 2nd test
|
||||
// [1, 0, 0, 1, 1, 0, 2, 1] return [0, 0, 0, 1, 1, 1, 1, 2]
|
||||
std::vector<uint64_t> array2 = {1, 0, 0, 1, 1, 0, 2, 1};
|
||||
std::cout << "2nd test... ";
|
||||
sorting::selection_sort_recursive::selectionSortRecursive(array2);
|
||||
assert(std::is_sorted(std::begin(array2), std::end(array2)));
|
||||
std::cout << "passed" << std::endl;
|
||||
// 3rd test
|
||||
// [1, 1, 0, 0, 1, 2, 2, 0, 2, 1] return [0, 0, 0, 1, 1, 1, 1, 2, 2, 2]
|
||||
std::vector<uint64_t> array3 = {1, 1, 0, 0, 1, 2, 2, 0, 2, 1};
|
||||
std::cout << "3rd test... ";
|
||||
sorting::selection_sort_recursive::selectionSortRecursive(array3);
|
||||
assert(std::is_sorted(std::begin(array3), std::end(array3)));
|
||||
std::cout << "passed" << std::endl;
|
||||
// 4th test
|
||||
// [2, 2, 2, 0, 0, 1, 1] return [0, 0, 1, 1, 2, 2, 2]
|
||||
std::vector<uint64_t> array4 = {2, 2, 2, 0, 0, 1, 1};
|
||||
std::cout << "4th test... ";
|
||||
sorting::selection_sort_recursive::selectionSortRecursive(array4);
|
||||
assert(std::is_sorted(std::begin(array4), std::end(array4)));
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
int size = 10;
|
||||
int* array = new int[size];
|
||||
// Input
|
||||
std::cout << "\nHow many numbers do want to enter in unsorted array : ";
|
||||
std::cin >> size;
|
||||
std::cout << "\nEnter the numbers for unsorted array : ";
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::cin >> array[i];
|
||||
}
|
||||
|
||||
// Sorting
|
||||
for (int i = size / 2; i > 0; i = i / 2) {
|
||||
for (int j = i; j < size; j++) {
|
||||
for (int k = j - i; k >= 0; k = k - i) {
|
||||
if (array[k] < array[k + i]) {
|
||||
break;
|
||||
} else {
|
||||
int temp = array[k + i];
|
||||
array[k + i] = array[k];
|
||||
array[k] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output
|
||||
std::cout << "\nSorted array : ";
|
||||
for (int i = 0; i < size; ++i) {
|
||||
std::cout << array[i] << "\t";
|
||||
}
|
||||
|
||||
delete[] array;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief [Shell sort](https://en.wikipedia.org/wiki/Shell_sort) algorithm
|
||||
* \author [Krishna Vedala](https://github.com/kvedala)
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <utility> // for std::swap
|
||||
#include <vector>
|
||||
|
||||
/** pretty print array
|
||||
* \param[in] arr array to print
|
||||
* \param[in] LEN length of array to print
|
||||
*/
|
||||
template <class T>
|
||||
void show_data(T *arr, size_t LEN) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < LEN; i++) {
|
||||
std::cout << arr[i] << ", ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/** pretty print array
|
||||
* \param[in] arr array to print
|
||||
* \param[in] N length of array to print
|
||||
*/
|
||||
template <typename T, size_t N>
|
||||
void show_data(T (&arr)[N]) {
|
||||
show_data(arr, N);
|
||||
}
|
||||
|
||||
/** \namespace sorting
|
||||
* \brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* Optimized algorithm - takes half the time by utilizing
|
||||
* Mar
|
||||
**/
|
||||
template <typename T>
|
||||
void shell_sort(T *arr, size_t LEN) {
|
||||
const unsigned int gaps[] = {701, 301, 132, 57, 23, 10, 4, 1};
|
||||
const unsigned int gap_len = 8;
|
||||
size_t i, j, g;
|
||||
|
||||
for (g = 0; g < gap_len; g++) {
|
||||
unsigned int gap = gaps[g];
|
||||
for (i = gap; i < LEN; i++) {
|
||||
T tmp = arr[i];
|
||||
|
||||
for (j = i; j >= gap && (arr[j - gap] - tmp) > 0; j -= gap) {
|
||||
arr[j] = arr[j - gap];
|
||||
}
|
||||
|
||||
arr[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** function overload - when input array is of a known length array type
|
||||
*/
|
||||
template <typename T, size_t N>
|
||||
void shell_sort(T (&arr)[N]) {
|
||||
shell_sort(arr, N);
|
||||
}
|
||||
|
||||
/** function overload - when input array is of type std::vector,
|
||||
* simply send the data content and the data length to the above function.
|
||||
*/
|
||||
template <typename T>
|
||||
void shell_sort(std::vector<T> *arr) {
|
||||
shell_sort(arr->data(), arr->size());
|
||||
}
|
||||
|
||||
} // namespace sorting
|
||||
|
||||
using sorting::shell_sort;
|
||||
|
||||
/**
|
||||
* function to compare sorting using cstdlib's qsort
|
||||
**/
|
||||
template <typename T>
|
||||
int compare(const void *a, const void *b) {
|
||||
T arg1 = *static_cast<const T *>(a);
|
||||
T arg2 = *static_cast<const T *>(b);
|
||||
|
||||
if (arg1 < arg2)
|
||||
return -1;
|
||||
if (arg1 > arg2)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
// return (arg1 > arg2) - (arg1 < arg2); // possible shortcut
|
||||
// return arg1 - arg2; // erroneous shortcut (fails if INT_MIN is present)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test implementation of shell_sort on integer arrays by comparing results
|
||||
* against std::qsort.
|
||||
*/
|
||||
void test_int(const int NUM_DATA) {
|
||||
// int array = new int[NUM_DATA];
|
||||
int *data = new int[NUM_DATA];
|
||||
int *data2 = new int[NUM_DATA];
|
||||
// int array2 = new int[NUM_DATA];
|
||||
int range = 1800;
|
||||
|
||||
for (int i = 0; i < NUM_DATA; i++)
|
||||
data[i] = data2[i] = (std::rand() % range) - (range >> 1);
|
||||
|
||||
/* sort using our implementation */
|
||||
std::clock_t start = std::clock();
|
||||
shell_sort(data, NUM_DATA);
|
||||
std::clock_t end = std::clock();
|
||||
double elapsed_time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
|
||||
std::cout << "Time spent sorting using shell_sort2: " << elapsed_time
|
||||
<< "s\n";
|
||||
|
||||
/* sort using std::qsort */
|
||||
start = std::clock();
|
||||
std::qsort(data2, NUM_DATA, sizeof(data2[0]), compare<int>);
|
||||
end = std::clock();
|
||||
|
||||
elapsed_time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
|
||||
std::cout << "Time spent sorting using std::qsort: " << elapsed_time
|
||||
<< "s\n";
|
||||
|
||||
for (int i = 0; i < NUM_DATA; i++) {
|
||||
assert(data[i] == data2[i]); // ensure that our sorting results match
|
||||
// the standard results
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
delete[] data2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test implementation of shell_sort on float arrays by comparing results
|
||||
* against std::qsort.
|
||||
*/
|
||||
void test_f(const int NUM_DATA) {
|
||||
// int array = new int[NUM_DATA];
|
||||
float *data = new float[NUM_DATA];
|
||||
float *data2 = new float[NUM_DATA];
|
||||
// int array2 = new int[NUM_DATA];
|
||||
int range = 1000;
|
||||
|
||||
for (int i = 0; i < NUM_DATA; i++) {
|
||||
data[i] = data2[i] = ((std::rand() % range) - (range >> 1)) / 100.;
|
||||
}
|
||||
|
||||
/* sort using our implementation */
|
||||
std::clock_t start = std::clock();
|
||||
shell_sort(data, NUM_DATA);
|
||||
std::clock_t end = std::clock();
|
||||
double elapsed_time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
|
||||
std::cout << "Time spent sorting using shell_sort2: " << elapsed_time
|
||||
<< "s\n";
|
||||
|
||||
/* sort using std::qsort */
|
||||
start = std::clock();
|
||||
std::qsort(data2, NUM_DATA, sizeof(data2[0]), compare<float>);
|
||||
end = std::clock();
|
||||
|
||||
elapsed_time = static_cast<double>(end - start) / CLOCKS_PER_SEC;
|
||||
std::cout << "Time spent sorting using std::qsort: " << elapsed_time
|
||||
<< "s\n";
|
||||
|
||||
for (int i = 0; i < NUM_DATA; i++) {
|
||||
assert(data[i] == data2[i]); // ensure that our sorting results match
|
||||
// the standard results
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
delete[] data2;
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main(int argc, char *argv[]) {
|
||||
// initialize random number generator - once per program
|
||||
std::srand(std::time(NULL));
|
||||
|
||||
test_int(100); // test with sorting random array of 100 values
|
||||
std::cout << "Test 1 - 100 int values - passed. \n";
|
||||
test_int(1000); // test with sorting random array of 1000 values
|
||||
std::cout << "Test 2 - 1000 int values - passed.\n";
|
||||
test_int(10000); // test with sorting random array of 10000 values
|
||||
std::cout << "Test 3 - 10000 int values - passed.\n";
|
||||
|
||||
test_f(100); // test with sorting random array of 100 values
|
||||
std::cout << "Test 1 - 100 float values - passed. \n";
|
||||
test_f(1000); // test with sorting random array of 1000 values
|
||||
std::cout << "Test 2 - 1000 float values - passed.\n";
|
||||
test_f(10000); // test with sorting random array of 10000 values
|
||||
std::cout << "Test 3 - 10000 float values - passed.\n";
|
||||
|
||||
int i, NUM_DATA;
|
||||
|
||||
if (argc == 2)
|
||||
NUM_DATA = atoi(argv[1]);
|
||||
else
|
||||
NUM_DATA = 200;
|
||||
|
||||
// int array = new int[NUM_DATA];
|
||||
int *data = new int[NUM_DATA];
|
||||
// int array2 = new int[NUM_DATA];
|
||||
int range = 1800;
|
||||
|
||||
std::srand(time(NULL));
|
||||
for (i = 0; i < NUM_DATA; i++) {
|
||||
// allocate random numbers in the given range
|
||||
data[i] = (std::rand() % range) - (range >> 1);
|
||||
}
|
||||
|
||||
std::cout << "Unsorted original data: " << std::endl;
|
||||
show_data(data, NUM_DATA);
|
||||
std::clock_t start = std::clock();
|
||||
shell_sort(data, NUM_DATA); // perform sorting
|
||||
std::clock_t end = std::clock();
|
||||
|
||||
std::cout << std::endl
|
||||
<< "Data Sorted using custom implementation: " << std::endl;
|
||||
show_data(data, NUM_DATA);
|
||||
|
||||
double elapsed_time = (end - start) * 1.f / CLOCKS_PER_SEC;
|
||||
std::cout << "Time spent sorting: " << elapsed_time << "s\n" << std::endl;
|
||||
|
||||
delete[] data;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Returns the sorted vector after performing SlowSort
|
||||
// It is a sorting algorithm that is of humorous nature and not useful.
|
||||
// It's based on the principle of multiply and surrender, a tongue-in-cheek joke
|
||||
// of divide and conquer. It was published in 1986 by Andrei Broder and Jorge
|
||||
// Stolfi in their paper Pessimal Algorithms and Simplexity Analysis. This
|
||||
// algorithm multiplies a single problem into multiple subproblems It is
|
||||
// interesting because it is provably the least efficient sorting algorithm that
|
||||
// can be built asymptotically, and with the restriction that such an algorithm,
|
||||
// while being slow, must still all the time be working towards a result.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void SlowSort(int a[], int i, int j) {
|
||||
if (i >= j)
|
||||
return;
|
||||
int m = i + (j - i) / 2; // midpoint, implemented this way to avoid
|
||||
// overflow
|
||||
int temp;
|
||||
SlowSort(a, i, m);
|
||||
SlowSort(a, m + 1, j);
|
||||
if (a[j] < a[m]) {
|
||||
temp = a[j]; // swapping a[j] & a[m]
|
||||
a[j] = a[m];
|
||||
a[m] = temp;
|
||||
}
|
||||
SlowSort(a, i, j - 1);
|
||||
}
|
||||
|
||||
// Sample Main function
|
||||
|
||||
int main() {
|
||||
int size;
|
||||
std::cout << "\nEnter the number of elements : ";
|
||||
|
||||
std::cin >> size;
|
||||
|
||||
int *arr = new int[size];
|
||||
|
||||
std::cout << "\nEnter the unsorted elements : ";
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
std::cout << "\n";
|
||||
std::cin >> arr[i];
|
||||
}
|
||||
|
||||
SlowSort(arr, 0, size);
|
||||
|
||||
std::cout << "Sorted array\n";
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
std::cout << arr[i] << " ";
|
||||
}
|
||||
|
||||
delete[] arr;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Stooge sort implementation](https://en.wikipedia.org/wiki/Stooge_sort)
|
||||
* in C++
|
||||
* @details
|
||||
* Stooge sort is a recursive sorting algorithm.
|
||||
* It divides the array into 3 parts and proceeds to:
|
||||
* - sort first two thirds of the array
|
||||
* - sort last two thirds of the array
|
||||
* - sort first two thirds of the array
|
||||
* It's time complexity is O(n^(log3/log1.5)), which is about O(n^2.7),
|
||||
* which makes it to be not the most efficient sorting algorithm
|
||||
* on the street on average. Space complexity is O(1).
|
||||
*/
|
||||
|
||||
#include <vector> /// for vector
|
||||
#include <cassert> /// for assert
|
||||
#include <algorithm> /// for std::is_sorted
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @brief The stoogeSort() function is used for sorting the array.
|
||||
* @param L - vector of values (int) to be sorted in in place (ascending order)
|
||||
* @param i - the first index of the array (0)
|
||||
* @param j - the last index of the array (L.size() - 1)
|
||||
* @returns void
|
||||
*/
|
||||
void stoogeSort(std::vector<int>* L, size_t i, size_t j) {
|
||||
if (i >= j) {
|
||||
return;
|
||||
}
|
||||
if ((*L)[i] > (*L)[j]) {
|
||||
std::swap((*L)[i], (*L)[j]);
|
||||
}
|
||||
if (j - i > 1) {
|
||||
size_t third = (j - i + 1) / 3;
|
||||
stoogeSort(L, i, j - third);
|
||||
stoogeSort(L, i + third, j);
|
||||
stoogeSort(L, i, j - third);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to test sorting algorithm
|
||||
* @returns void
|
||||
*/
|
||||
void test1() {
|
||||
std::vector<int> L = { 8, 9, 10, 4, 3, 5, 1 };
|
||||
stoogeSort(&L, 0, L.size() - 1);
|
||||
assert(std::is_sorted(std::begin(L), std::end(L)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to test sorting algorithm, one element
|
||||
* @returns void
|
||||
*/
|
||||
void test2() {
|
||||
std::vector<int> L = { -1 };
|
||||
stoogeSort(&L, 0, L.size() - 1);
|
||||
assert(std::is_sorted(std::begin(L), std::end(L)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to test sorting algorithm, repeating elements
|
||||
* @returns void
|
||||
*/
|
||||
void test3() {
|
||||
std::vector<int> L = { 1, 2, 5, 4, 1, 5 };
|
||||
stoogeSort(&L, 0, L.size() - 1);
|
||||
assert(std::is_sorted(std::begin(L), std::end(L)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file strand_sort.cpp
|
||||
* @brief Implementation of [Strand Sort](https://en.wikipedia.org/wiki/Strand_sort) algorithm.
|
||||
*
|
||||
* @details
|
||||
* Strand Sort is a sorting algorithm that works in \f$O(n)\f$ time if list is already sorted and works in \f$O(n^2)\f$ in worst case.
|
||||
*
|
||||
* It is passed over the array to be sorted once and the ascending (sequential) numbers are taken.
|
||||
* After the first iteration, the sequential sub-array is put on the empty sorted array.
|
||||
* The main sequence is passed over again and a new sub-sequence is created in order.
|
||||
* Now that the sorted array is not empty, the newly extracted substring is merged with the sorted array.
|
||||
* Repeat types 3 and 4 until the sub-sequence and main sequence are empty.
|
||||
*
|
||||
* @author [Mertcan Davulcu](https://github.com/mertcandav)
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace strand
|
||||
* @brief Functions for [Strand Sort](https://en.wikipedia.org/wiki/Strand_sort) algorithm
|
||||
*/
|
||||
namespace strand {
|
||||
/**
|
||||
* @brief Apply sorting
|
||||
* @tparam element type of list
|
||||
* @param lst List to be sorted
|
||||
* @returns Sorted list<T> instance
|
||||
*/
|
||||
template <typename T>
|
||||
std::list<T> strand_sort(std::list<T> lst) {
|
||||
if (lst.size() < 2) { // Returns list if empty or contains only one element
|
||||
return lst; // Returns list
|
||||
}
|
||||
std::list<T> result; // Define new "result" named list instance.
|
||||
std::list<T> sorted; // Define new "sorted" named list instance.
|
||||
while(!lst.empty()) /* if lst is not empty */ {
|
||||
sorted.push_back(lst.front()); // Adds the first element of "lst" list to the bottom of the "sorted" list.
|
||||
lst.pop_front(); // Remove first element of "lst" list.
|
||||
for (auto it = lst.begin(); it != lst.end(); ) { // Return the loop as long as the current iterator is not equal to the last literator of the "lst" list.
|
||||
if (sorted.back() <= *it) { // If the last reference of the "sorted" list is less than or equal to the current iterator reference.
|
||||
sorted.push_back(*it); // Adds the iterator retrieved in the loop under the "sorted" list.
|
||||
it = lst.erase(it); // Deletes the element with the current iterator and assigns the deleted element to the iterator.
|
||||
} else {
|
||||
it++; // Next iterator.
|
||||
}
|
||||
}
|
||||
result.merge(sorted); // Merge "result" list with "sorted" list.
|
||||
}
|
||||
return result; // Returns sorted list
|
||||
}
|
||||
} // namespace strand
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Function for testing
|
||||
* @return N/A
|
||||
*/
|
||||
static void test() {
|
||||
std::list<int> lst = { -333, 525, 1, 0, 94, 52, 33 };
|
||||
|
||||
std::cout << "Before: ";
|
||||
for(auto item: lst) {
|
||||
std::cout << item << " ";
|
||||
}
|
||||
|
||||
lst = sorting::strand::strand_sort(lst); // Sort list.
|
||||
|
||||
std::cout << "\nAfter: ";
|
||||
for(auto item: lst) {
|
||||
std::cout << item << " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// C++ program to find minimum number of swaps required to sort an array
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// Function returns the minimum number of swaps
|
||||
// required to sort the array
|
||||
int minSwaps(int arr[], int n) {
|
||||
// Create an array of pairs where first
|
||||
// element is array element and second element
|
||||
// is position of first element
|
||||
std::pair<int, int> *arrPos = new std::pair<int, int>[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
arrPos[i].first = arr[i];
|
||||
arrPos[i].second = i;
|
||||
}
|
||||
|
||||
// Sort the array by array element values to
|
||||
// get right position of every element as second
|
||||
// element of pair.
|
||||
std::sort(arrPos, arrPos + n);
|
||||
|
||||
// To keep track of visited elements. Initialize
|
||||
// all elements as not visited or false.
|
||||
std::vector<bool> vis(n, false);
|
||||
|
||||
// Initialize result
|
||||
int ans = 0;
|
||||
|
||||
// Traverse array elements
|
||||
for (int i = 0; i < n; i++) {
|
||||
// already swapped and corrected or
|
||||
// already present at correct pos
|
||||
if (vis[i] || arrPos[i].second == i)
|
||||
continue;
|
||||
|
||||
// find out the number of node in
|
||||
// this cycle and add in ans
|
||||
int cycle_size = 0;
|
||||
int j = i;
|
||||
while (!vis[j]) {
|
||||
vis[j] = 1;
|
||||
|
||||
// move to next node
|
||||
j = arrPos[j].second;
|
||||
cycle_size++;
|
||||
}
|
||||
|
||||
// Update answer by adding current cycle.
|
||||
if (cycle_size > 0) {
|
||||
ans += (cycle_size - 1);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] arrPos;
|
||||
|
||||
// Return result
|
||||
return ans;
|
||||
}
|
||||
|
||||
// program to test
|
||||
int main() {
|
||||
int arr[] = {6, 7, 8, 1, 2, 3, 9, 12};
|
||||
int n = (sizeof(arr) / sizeof(int));
|
||||
std::cout << minSwaps(arr, n);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
// C++ program to perform TimSort.
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
|
||||
const int RUN = 32;
|
||||
|
||||
// this function sorts array from left index to to right index which is of size
|
||||
// atmost RUN
|
||||
void insertionSort(int arr[], int left, int right) {
|
||||
for (int i = left + 1; i <= right; i++) {
|
||||
const int temp = arr[i];
|
||||
int j = i - 1;
|
||||
while (j >= left && arr[j] > temp) {
|
||||
arr[j + 1] = arr[j];
|
||||
j--;
|
||||
}
|
||||
arr[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// merge function merges the sorted runs
|
||||
void merge(int arr[], int l, int m, int r) {
|
||||
// original array is broken in two parts, left and right array
|
||||
const int len1 = m - l + 1, len2 = r - m;
|
||||
int *left = new int[len1], *right = new int[len2];
|
||||
for (int i = 0; i < len1; i++) left[i] = arr[l + i];
|
||||
for (int i = 0; i < len2; i++) right[i] = arr[m + 1 + i];
|
||||
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = l;
|
||||
|
||||
// after comparing, we merge those two array in larger sub array
|
||||
while (i < len1 && j < len2) {
|
||||
if (left[i] <= right[j]) {
|
||||
arr[k] = left[i];
|
||||
i++;
|
||||
} else {
|
||||
arr[k] = right[j];
|
||||
j++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
// copy remaining elements of left, if any
|
||||
while (i < len1) {
|
||||
arr[k] = left[i];
|
||||
k++;
|
||||
i++;
|
||||
}
|
||||
|
||||
// copy remaining element of right, if any
|
||||
while (j < len2) {
|
||||
arr[k] = right[j];
|
||||
k++;
|
||||
j++;
|
||||
}
|
||||
delete[] left;
|
||||
delete[] right;
|
||||
}
|
||||
|
||||
// iterative Timsort function to sort the array[0...n-1] (similar to merge sort)
|
||||
void timSort(int arr[], int n) {
|
||||
// Sort individual subarrays of size RUN
|
||||
for (int i = 0; i < n; i += RUN)
|
||||
insertionSort(arr, i, std::min((i + 31), (n - 1)));
|
||||
|
||||
// start merging from size RUN (or 32). It will merge to form size 64, then
|
||||
// 128, 256 and so on ....
|
||||
for (int size = RUN; size < n; size = 2 * size) {
|
||||
// pick starting point of left sub array. We are going to merge
|
||||
// arr[left..left+size-1] and arr[left+size, left+2*size-1] After every
|
||||
// merge, we increase left by 2*size
|
||||
for (int left = 0; left < n; left += 2 * size) {
|
||||
// find ending point of left sub array
|
||||
// mid+1 is starting point of right sub array
|
||||
const int mid = std::min((left + size - 1), (n - 1));
|
||||
const int right = std::min((left + 2 * size - 1), (n - 1));
|
||||
|
||||
// merge sub array arr[left.....mid] & arr[mid+1....right]
|
||||
merge(arr, left, mid, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// utility function to print the Array
|
||||
void printArray(int arr[], int n) {
|
||||
for (int i = 0; i < n; i++) printf("%d ", arr[i]);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief self-test implementation
|
||||
* @returns void
|
||||
*/
|
||||
void tests() {
|
||||
// Case: array of length 65
|
||||
constexpr int N = 65;
|
||||
int arr[N];
|
||||
|
||||
std::iota(arr, arr + N, 0);
|
||||
std::reverse(arr, arr + N);
|
||||
assert(!std::is_sorted(arr, arr + N));
|
||||
|
||||
timSort(arr, N);
|
||||
assert(std::is_sorted(arr, arr + N));
|
||||
}
|
||||
|
||||
// Driver program to test above function
|
||||
int main() {
|
||||
tests(); // run self test implementations
|
||||
|
||||
int arr[] = {5, 21, 7, 23, 19};
|
||||
const int n = sizeof(arr) / sizeof(arr[0]);
|
||||
printf("Given Array is\n");
|
||||
printArray(arr, n);
|
||||
|
||||
timSort(arr, n);
|
||||
|
||||
printf("After Sorting Array is\n");
|
||||
printArray(arr, n);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Wave
|
||||
* sort](https://www.geeksforgeeks.org/sort-array-wave-form-2/) algorithm
|
||||
* @details
|
||||
* Wave Sort is a sorting algorithm that works in \f$O(nlogn)\f$ time assuming
|
||||
* the sort function used works in \f$O(nlogn)\f$ time.
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::is_sorted, std::swap
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace wave_sort
|
||||
* @brief Functions for the [Wave
|
||||
* sort](https://www.geeksforgeeks.org/sort-array-wave-form-2/) implementation
|
||||
*/
|
||||
namespace wave_sort {
|
||||
/**
|
||||
* @brief The main function implements that implements the Wave Sort algorithm
|
||||
* @tparam T type of array
|
||||
* @param in_arr array to be sorted
|
||||
* @returns arr the wave sorted array
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<T> waveSort(const std::vector<T> &in_arr, int64_t n) {
|
||||
std::vector<T> arr(in_arr);
|
||||
|
||||
for (int64_t i = 0; i < n; i++) {
|
||||
arr[i] = in_arr[i];
|
||||
}
|
||||
std::sort(arr.begin(), arr.end());
|
||||
for (int64_t i = 0; i < n - 1; i += 2) { // swap all the adjacent elements
|
||||
std::swap(arr[i], arr[i + 1]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
} // namespace wave_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// [10, 90, 49, 2, 1, 5, 23] return [2, 1, 10, 5, 49, 23, 90]
|
||||
std::vector<int64_t> array1 = {10, 90, 49, 2, 1, 5, 23};
|
||||
std::cout << "Test 1... ";
|
||||
std::vector<int64_t> arr1 = sorting::wave_sort::waveSort(array1, 7);
|
||||
const std::vector<int64_t> o1 = {2, 1, 10, 5, 49, 23, 90};
|
||||
assert(arr1 == o1);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// [1, 3, 4, 2, 7, 8] return [2, 1, 4, 3, 8, 7]
|
||||
std::vector<int64_t> array2 = {1, 3, 4, 2, 7, 8};
|
||||
std::cout << "Test 2... ";
|
||||
std::vector<int64_t> arr2 = sorting::wave_sort::waveSort(array2, 6);
|
||||
const std::vector<int64_t> o2 = {2, 1, 4, 3, 8, 7};
|
||||
assert(arr2 == o2);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// [3, 3, 3, 3] return [3, 3, 3, 3]
|
||||
std::vector<int64_t> array3 = {3, 3, 3, 3};
|
||||
std::cout << "Test 3... ";
|
||||
std::vector<int64_t> arr3 = sorting::wave_sort::waveSort(array3, 4);
|
||||
const std::vector<int64_t> o3 = {3, 3, 3, 3};
|
||||
assert(arr3 == o3);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// [9, 4, 6, 8, 14, 3] return [4, 3, 8, 6, 14, 9]
|
||||
std::vector<int64_t> array4 = {9, 4, 6, 8, 14, 3};
|
||||
std::cout << "Test 4... ";
|
||||
std::vector<int64_t> arr4 = sorting::wave_sort::waveSort(array4, 6);
|
||||
const std::vector<int64_t> o4 = {4, 3, 8, 6, 14, 9};
|
||||
assert(arr4 == o4);
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* \addtogroup sorting Sorting Algorithms
|
||||
* @{
|
||||
* \file
|
||||
* \brief [Wiggle Sort Algorithm]
|
||||
* (https://leetcode.com/problems/wiggle-sort-ii/) Implementation
|
||||
*
|
||||
* \author [Roshan Kanwar](http://github.com/roshan0708)
|
||||
*
|
||||
* \details
|
||||
* Wiggle Sort sorts the array into a wave like array.
|
||||
* An array ‘arr[0..n-1]’ is sorted in wave form,
|
||||
* if arr[0] >= arr[1] <= arr[2] >= arr[3] <= arr[4] >= …..
|
||||
*
|
||||
* \example
|
||||
* arr = [1,1,5,6,1,4], after wiggle sort arr will become equal to [1,1,6,1,5,4]
|
||||
* arr = [2,8,9,1,7], after wiggle sort arr will become equal to [8,2,9,1,7]
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <iostream> /// for io operations
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace wiggle_sort
|
||||
* @brief Functions for [Wiggle
|
||||
* Sort](https://leetcode.com/problems/wiggle-sort-ii/) algorithm
|
||||
*/
|
||||
namespace wiggle_sort {
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Function used for sorting the elements in wave form.
|
||||
* @details
|
||||
* Checking whether the even indexed elements are greater than
|
||||
* their adjacent odd elements.
|
||||
* Traversing all even indexed elements of the input arr.
|
||||
* If current element is smaller than the previous odd element, swap them.
|
||||
* If current element is smaller than the next odd element, swap them.
|
||||
*
|
||||
* @param arr input array (unsorted elements)
|
||||
*
|
||||
*/
|
||||
template <typename T> // this allows to have vectors of ints, double, float,
|
||||
// etc
|
||||
std::vector<T> wiggleSort(const std::vector<T> &arr) {
|
||||
uint32_t size = arr.size();
|
||||
|
||||
std::vector<T> out(
|
||||
arr); // create a copy of input vector. this way, the original input
|
||||
// vector does not get modified. a sorted array is is returned.
|
||||
|
||||
for (int i = 0; i < size; i += 2) {
|
||||
if (i > 0 && out[i - 1] > out[i]) {
|
||||
std::swap(out[i], out[i - 1]); // swapping the two values
|
||||
}
|
||||
|
||||
if (i < size - 1 && out[i] < out[i + 1]) {
|
||||
std::swap(out[i], out[i + 1]); // swapping the two values
|
||||
}
|
||||
}
|
||||
|
||||
return out; // returns the sorted vector
|
||||
}
|
||||
} // namespace wiggle_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Utility function used for printing the elements.
|
||||
* Prints elements of the array after they're sorted using wiggle sort
|
||||
* algorithm.
|
||||
*
|
||||
* @param arr array containing the sorted elements
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
static void displayElements(const std::vector<T> &arr) {
|
||||
uint32_t size = arr.size();
|
||||
|
||||
std::cout << "Sorted elements are as follows: ";
|
||||
|
||||
std::cout << "[";
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::cout << arr[i];
|
||||
if (i != size - 1) {
|
||||
std::cout << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test function
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::srand(std::time(nullptr)); // initialize random number generator
|
||||
|
||||
std::vector<float> data1(100);
|
||||
for (auto &d : data1) { // generate random numbers between -5.0 and 4.99
|
||||
d = float(std::rand() % 1000 - 500) / 100.f;
|
||||
}
|
||||
|
||||
std::vector<float> sorted = sorting::wiggle_sort::wiggleSort<float>(data1);
|
||||
|
||||
displayElements(sorted);
|
||||
|
||||
for (uint32_t j = 0; j < data1.size(); j += 2) {
|
||||
assert(data1[j] <= data1[j + 1] &&
|
||||
data1[j + 1] >= data1[j + 2]); // check the validation condition
|
||||
}
|
||||
|
||||
std::cout << "Test 1 passed\n";
|
||||
}
|
||||
|
||||
/** Driver Code */
|
||||
int main() {
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
Reference in New Issue
Block a user