#pragma once #include #include namespace asp { template struct Array { std::shared_ptr data; size_t length = 0; Array() noexcept = delete; Array(const size_t& size) noexcept: data(std::shared_ptr(new T[size])), length(size) { // #ifdef __DEBUG // printf("Creating array of size %lu\n", size); // #endif } Array(const Array& other) noexcept: data(std::shared_ptr(new T[other.length])), length(other.length) { #ifdef __DEBUG printf("Copying array of size %lu\n", other.length); #endif memcpy(data.get(), other.data.get(), length * sizeof(T)); } Array(Array&& other) noexcept { // #ifdef __DEBUG // printf("Moving array of size %lu\n", other.length); // #endif data = other.data; length = other.length; other.data = nullptr; other.length = 0; } constexpr T& operator[](const size_t& index) const { #ifdef __DEBUG if (index > length) { fprintf(stderr, "Index %ld out of range in Array of length %ld !\n", index, length); throw std::out_of_range("Index out of range !"); } #endif return data.get()[index]; } }; template int print(const Array& a, const char* format) noexcept { int num_written = 0; num_written += printf("["); char formatter[BUFSIZ] = { 0 }; sprintf(formatter, "%s,", format); for (size_t i = 0; i < a.length; ++i) num_written += printf(formatter, a[i]); sprintf(formatter, "%s]\n", format); num_written += printf(formatter, a[a.length - 1]); return num_written; } int print(const Array& a) noexcept { return print(a, "%i"); } int print(const Array& a) noexcept { return print(a, "%lu"); } int print(const Array& a) noexcept { //printf("%i\n", a[0]); return print(a, "%i"); } int print(const std::string& s) noexcept { return printf("%s\n", s.c_str()); } int print(const char* s) noexcept { return printf("%s\n", s); } template constexpr T& max(const Array& a) noexcept { T& max_el = a[0]; for (size_t i = 1; i < a.length; ++i) if (a[i] > max_el) max_el = a[i]; return max_el; } template constexpr T& min(const Array& a) noexcept { T& max_el = a[0]; for (size_t i = 1; i < a.length; ++i) if (a[i] < max_el) max_el = a[i]; return max_el; } template Array& map(Array& a, const F& fnc) noexcept { for (size_t i = 0; i < a.length; ++i) a[i] = fnc(i, a[i]); return a; } template void foreach(const Array& a, const F& fnc) noexcept { for (size_t i = 0; i < a.length; ++i) fnc(i, a[i]); } Array range(const size_t& n) noexcept { Array a(n); return std::move(map(a, [](const size_t& i, const size_t&) -> const size_t& { return i; })); } template constexpr inline static void swap(T* a, T* b) noexcept { const T temp = *a; *a = *b; *b = temp; } template void bubble_sort(const Array& a) noexcept { size_t j; for (size_t i = 0; i < a.length; ++i) for (j = i + 1; j < a.length; ++j) if (a[i] > a[j]) swap(&a[i], &a[j]); } template Array bubble_sort_arg(const Array& a) noexcept { Array indices = range(a.length); size_t j; for (size_t i = 0; i < a.length; ++i) for (j = i + 1; j < a.length; ++j) if (a[i] > a[j]){ swap(&indices[i], &indices[j]); swap(&a[i], &a[j]); } return indices; } template static size_t qs_partition(const Array& a, const size_t& l, const size_t& h) noexcept { size_t i = l - 1; for (size_t j = l; j <= h; ++j) if (a[j] < a[h]) swap(&a[++i], &a[j]); swap(&a[++i], &a[h]); return i; } template static void quicksort(const Array& a, const size_t& l, const size_t& h) noexcept { if (l >= h) return; const size_t p = qs_partition(a, l, h); if (p - 1 <= h) quicksort(a, l, p - 1); quicksort(a, p + 1, h); } template void quicksort(const Array& a) noexcept { quicksort(a, 0, a.length - 1); } template static void quicksort_iter(const Array& a, const size_t& l, const size_t& h) noexcept { // Create an auxiliary stack const size_t total = h - l + 1; // push initial values of l and h to stack size_t* stack = new size_t[total]{l, h}; // initialize top of stack size_t top = 1; size_t low = l, high = h; // Keep popping from stack while is not empty while (top <= total) { // Pop h and l high = stack[top--]; low = stack[top--]; if(low >= high) break; // Set pivot element at its correct position // in sorted array const size_t p = qs_partition(a, low, high); // If there are elements on left side of pivot, // then push left side to stack if (p - 1 > low && p - 1 < total) { stack[++top] = low; stack[++top] = p - 1; } // If there are elements on right side of pivot, // then push right side to stack if (p + 1 < high) { stack[++top] = p + 1; stack[++top] = high; } } delete[] stack; } template void quicksort_iter(const Array& a) noexcept { quicksort_iter(a, 0, a.length - 1); } template static size_t qs_arg_partition(const Array& a, const Array& indices, const size_t& l, const size_t& h) noexcept { size_t i = l - 1; for (size_t j = l; j <= h; ++j) if (a[j] < a[h]){ swap(&a[++i], &a[j]); swap(&indices[i], &indices[j]); } swap(&indices[++i], &indices[h]); swap(&a[i], &a[h]); return i; } template static void quicksort_arg(const Array& a, const Array& indices, const size_t& l, const size_t& h) noexcept { if (l >= h) return; const size_t p = qs_arg_partition(a, indices, l, h); if (p - 1 <= h) quicksort_arg(a, indices, l, p - 1); quicksort_arg(a, indices, p + 1, h); } template Array quicksort_arg(const Array& other, const size_t& l, const size_t& h) noexcept { Array indices = range(other.length); quicksort_arg(other, indices, l, h); return indices; } template Array quicksort_arg(const Array& a) noexcept { return quicksort_arg(a, 0, a.length - 1); } template void quicksort_arg_iter(const Array& a, const Array& indices, const size_t& l, const size_t& h) noexcept { // Create an auxiliary stack const size_t total = h - l + 1; // push initial values of l and h to stack size_t* stack = new size_t[total]{l,h}; // initialize top of stack size_t top = 1; size_t low = l, high = h; // Keep popping from stack while is not empty while (top <= total) { // Pop h and l high = stack[top--]; low = stack[top--]; if(low >= high) break; // Set pivot element at its correct position // in sorted array const size_t p = qs_arg_partition(a, indices, low, high); // If there are elements on left side of pivot, // then push left side to stack if (p - 1 > low && p - 1 < total) { stack[++top] = low; stack[++top] = p - 1; } // If there are elements on right side of pivot, // then push right side to stack if (p + 1 < high) { stack[++top] = p + 1; stack[++top] = high; } } delete[] stack; } template Array quicksort_arg_iter(const Array& a) noexcept { Array indices = range(a.length); quicksort_arg_iter(a, indices, 0, a.length - 1); return indices; } template struct ArgVal { size_t indice; T val; ArgVal() noexcept = default; ArgVal(const size_t& _i, const T& _v) noexcept : indice(_i), val(_v) {} constexpr bool operator>(const ArgVal& other) const noexcept { return std::move(val > other.val); } constexpr bool operator<(const ArgVal& other) const noexcept { return std::move(val < other.val); } constexpr bool operator>=(const ArgVal& other) const noexcept { return std::move(val >= other.val); } constexpr bool operator<=(const ArgVal& other) const noexcept { return std::move(val <= other.val); } }; template static void merge(const Array& a, const size_t& l, const size_t& m, const size_t& r) noexcept { Array left_arr(m - l + 1); memcpy(&left_arr.data[0], &a[l], left_arr.length * sizeof(T)); Array right_arr(r - m); memcpy(&right_arr.data[0], &a[m + 1], right_arr.length * sizeof(T)); size_t i_a0 = 0, i_a1 = 0, i = l; // Merge the temp arrays back size_to array[left..right] for (; i_a0 < left_arr.length && i_a1 < right_arr.length; ++i) a[i] = left_arr[i_a0] <= right_arr[i_a1] ? left_arr[i_a0++] : right_arr[i_a1++]; // // Copy the remaining elements of left[], if there are any const size_t leftover = left_arr.length - i_a0; memcpy(&a[i], &left_arr[i_a0], leftover * sizeof(T)); // Copy the remaining elements of right[], if there are any memcpy(&a[i + leftover], &right_arr[i_a1], (right_arr.length - i_a1) * sizeof(T)); } template void mergesort(const Array& a, const size_t& l, const size_t& r) noexcept { if (l >= r) return; const size_t m = l + (r - l) / 2; mergesort(a, l, m); mergesort(a, m + 1, r); merge(a, l, m, r); } template void mergesort(const Array& a) noexcept { mergesort(a, 0, a.length - 1); } template Array mergesort_arg(const Array& a, const size_t& l, const size_t& r) noexcept { Array> temp_vals(a.length); map(temp_vals, [&a](const size_t& i, const ArgVal&) -> const ArgVal { return ArgVal(i, a[i]); }); mergesort(temp_vals, l, r); Array indices(a.length); return std::move(map(indices, [&temp_vals](const size_t& i, const size_t&) -> size_t { return temp_vals[i].indice; })); } template Array mergesort_arg(const Array& a) noexcept { return mergesort_arg(a, 0, a.length - 1); } //static void count_sort(const Array& a, const int& exp, const int& d) noexcept { // Array output(a.length), count(d); // memset(&count[0], 0, d * sizeof(int)); // foreach(a, [count, exp, d](const int&, const int& val) -> void { // count[(val / exp) % d]++; // }); // for (int i = 1; i <= d; ++i) // count[i] += count[i - 1]; // for (int i = a.length - 1; i >= 0; --i) { // output[count[(a[i] / exp) % d] - 1] = a[i]; // count[(a[i] / exp) % d]--; // } // memcpy(&a[0], &output[0], a.length * sizeof(int)); //} template void counting_sort(const Array& a) noexcept { Array output(a); map(a, [output](const size_t& i, const T&) -> const T& { return output[i]; }); } template Array counting_sort_arg(const Array& a) noexcept { Array indices = range(a.length); return indices; } template inline void radix_sort_256(T* a, const size_t& n) noexcept { //template //void radix_sort(const Array& a) noexcept { if (n <= 1) //if (a.length <= 1) return; T* output = new T[n]; // output array size_t* count = new size_t[256]; T* originalArr = a; // So we know which was input for (size_t shift = 0, s = 0; shift < 4; shift++, s += 8) { // Zero the counts for (size_t i = 0; i < 256; i++) count[i] = 0; // Store count of occurrences in count[] for (size_t i = 0; i < n; i++) count[(a[i] >> s) & 0xff]++; // Change count[i] so that count[i] now contains // actual position of this digit in output[] for (size_t i = 1; i < 256; i++) count[i] += count[i - 1]; // Build the output array for (int i = n - 1; i >= 0; i--) { // precalculate the offset as it's a few instructions const size_t idx = (a[i] >> s) & 0xff; // Subtract from the count and store the value output[--count[idx]] = a[i]; } // Copy the output array to input[], so that input[] // is sorted according to current digit // We can just swap the pointers swap(a, output); } // If we switched posize_ters an odd number of times, // make sure we copy before returning if (originalArr == output) { swap(a, output); for (size_t i = 0; i < n; i++) a[i] = output[i]; } delete[] output, delete[] count; } template void radix_sort(const Array& a) noexcept { radix_sort_256(a.data.get(), a.length); } template Array radix_sort_arg(const Array& a) noexcept { Array indices = range(a.length); return indices; } };