#pragma once #include #include #include #include #include #ifdef __DEBUG #include #endif namespace asp { template struct Array { std::shared_ptr data; size_t length = 0; constexpr Array(void) noexcept = delete; constexpr 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 } constexpr Array(const std::initializer_list& other) noexcept : data(std::shared_ptr(new T[other.size()])), length(other.size()) { #ifdef __DEBUG printf("Copying array of size %lu\n", other.size()); #endif memcpy(data.get(), other.begin(), length * sizeof(T)); } constexpr 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)); } constexpr 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 constexpr int32_t print(const Array& a, const char* const format) noexcept { int32_t num_written = 0; num_written += printf("["); char formatter[256] = { 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; } constexpr int32_t print(const Array& a) noexcept { return print(a, "%b"); } constexpr int32_t print(const Array& a) noexcept { return print(a, "%i"); } constexpr int32_t print(const Array& a) noexcept { return print(a, "%u"); } constexpr int32_t print(const Array& a) noexcept { return print(a, "%lu"); } constexpr int32_t print(const Array& a) noexcept { return print(a, "%i"); } constexpr int32_t print(const std::string_view& s) noexcept { return printf("%s\n", s.data()); } constexpr int32_t print(const char* const 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 constexpr 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 constexpr void foreach(const Array& a, const F& fnc) noexcept { for (size_t i = 0; i < a.length; ++i) fnc(i, a[i]); } inline Array range(const size_t& n) noexcept { Array a(n); return map(a, [](const size_t& i, const size_t&) -> const size_t& { return i; }); } template constexpr void swap(T* const a, T* const b) noexcept { const T temp = *a; *a = *b; *b = temp; } template constexpr void bubble_sort(const Array& a) noexcept { size_t j = 0; for (size_t i = 0; i < a.length; ++i) { bool swapped = false; for (j = i + 1; j < a.length; ++j) if (a[i] > a[j]) { swap(&a[i], &a[j]); swapped = true; } if (!swapped) break; } } 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) { bool swapped = false; for (j = i + 1; j < a.length; ++j) if (a[i] > a[j]) { swap(&indices[i], &indices[j]); swap(&a[i], &a[j]); swapped = true; } if (!swapped) break; } return indices; } template constexpr 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 constexpr 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 constexpr void quicksort(const Array& a) noexcept { quicksort(a, 0, a.length - 1); } template constexpr 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* const 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 constexpr void quicksort_iter(const Array& a) noexcept { quicksort_iter(a, 0, a.length - 1); } template constexpr 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 constexpr 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 constexpr 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* const stack = new size_t[total]{l,h}; // initialize top of stack size_t top = 1, 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; constexpr ArgVal(void) noexcept = default; constexpr 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 constexpr 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 constexpr 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 constexpr 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); } template constexpr void insertion_sort(const Array& a) noexcept { size_t j = 0; for(size_t i = 1; i < a.length; ++i) { T key = a[i]; for(j = i; j > 0 && a[j - 1] > key; --j) a[j] = a[j - 1]; a[j] = key; } } template Array insertion_argsort(const Array& a) noexcept { Array indices = range(a.length); size_t j = 0; for(size_t i = 1; i < a.length; ++i){ for(j = i; j > 0 && a[indices[j - 1]] > a[indices[i]]; --j) indices[j] = indices[j - 1]; indices[j] = i; } return indices; } template constexpr void counting_sort(const Array& a) noexcept { const size_t N = a.length; const T M = max(a); const T exp = 10; const T d = 128; Array countArray(M); memset(&countArray[0], 0, M * sizeof(T)); foreach(a, [&countArray](const size_t, const T val) -> void { ++countArray[val]; }); for (T i = 1; i <= M; ++i) countArray[i] += countArray[i - 1]; Array output(N); for (size_t i = N - 1; i > 0; --i){ output[countArray[a[i]] - 1] = a[i]; --countArray[a[i]]; } memmove(&a[0], &output[0], a.length * sizeof(T)); } template Array counting_sort_arg(const Array& a) noexcept { Array indices = range(a.length); return indices; } inline void countsort(int a[], int n, int pos){ int* output = new int[n + 1]; int max = (a[0] / pos) % 10; for (int i = 1; i < n; i++) { if (((a[i] / pos) % 10) > max) max = a[i]; } int* count = new int[max + 1]; for (int i = 0; i < max; ++i) count[i] = 0; for (int i = 0; i < n; i++) count[(a[i] / pos) % 10]++; for (int i = 1; i < 10; i++) count[i] += count[i - 1]; for (int i = n - 1; i >= 0; i--) { output[count[(a[i] / pos) % 10] - 1] = a[i]; count[(a[i] / pos) % 10]--; } for (int i = 0; i < n; i++) a[i] = output[i]; delete[] output; delete[] count; } // template // constexpr 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* const 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 (int32_t 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; // } constexpr void radix_sort_256(int32_t a[], int n){ int max = a[0]; for (int i = 1; i < n; i++) if (a[i] > max) max = a[i]; for (int pos = 1; max / pos > 0; pos *= 10) countsort(a, n, pos); } template constexpr void radix_sort(const Array& a) noexcept { radix_sort_256(a.data.get(), a.length); } // template // constexpr Array radix_sort_arg(const Array& a) noexcept { // Array indices = range(a.length); // // return indices; // } };