diff --git a/tasks/votincev_d_radixmerge_sort/omp/include/ops_omp.hpp b/tasks/votincev_d_radixmerge_sort/omp/include/ops_omp.hpp index 4c77a94ad..559533ddb 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/include/ops_omp.hpp +++ b/tasks/votincev_d_radixmerge_sort/omp/include/ops_omp.hpp @@ -24,5 +24,7 @@ class VotincevDRadixMergeSortOMP : public BaseTask { // ============================== // мои дополнительные функции === static void SortByDigit(std::vector &array, int32_t exp); + static void LocalRadixSort(uint32_t *begin, uint32_t *end); + static void Merge(const uint32_t *src, uint32_t *dst, int32_t left, int32_t mid, int32_t right); }; } // namespace votincev_d_radixmerge_sort diff --git a/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp b/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp index d96ac4c4b..8fdd0ee61 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp +++ b/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp @@ -3,8 +3,10 @@ #include #include +#include #include #include +#include #include #include "votincev_d_radixmerge_sort/common/include/common.hpp" @@ -24,63 +26,112 @@ bool VotincevDRadixMergeSortOMP::PreProcessingImpl() { return true; } -void VotincevDRadixMergeSortOMP::SortByDigit(std::vector &array, int32_t exp) { - std::vector> buckets(10); - - for (const auto &num : array) { - int32_t digit = (num / exp) % 10; - buckets[digit].push_back(num); +void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) { + auto n = static_cast(end - begin); + if (n <= 1) { + return; } - size_t index = 0; - for (int i = 0; i < 10; ++i) { - for (const auto &val : buckets[i]) { - array[index++] = val; + uint32_t max_val = *std::max_element(begin, end); + + std::vector buffer(static_cast(n)); + uint32_t *src = begin; + uint32_t *dst = buffer.data(); + + for (int64_t exp = 1; (static_cast(max_val) / exp) > 0; exp *= 10) { + std::array count{}; + + for (int32_t i = 0; i < n; ++i) { + count.at(static_cast((src[i] / exp) % 10))++; + } + for (int32_t i = 1; i < 10; ++i) { + count.at(static_cast(i)) += count.at(static_cast(i - 1)); } - buckets[i].clear(); + for (int32_t i = n - 1; i >= 0; --i) { + auto digit = static_cast((src[i] / exp) % 10); + + size_t target_idx = static_cast(count.at(digit)) - 1; + dst[target_idx] = src[i]; + + count.at(digit)--; + } + std::swap(src, dst); + } + + if (src != begin) { + std::copy(src, src + n, begin); } } -bool VotincevDRadixMergeSortOMP::RunImpl() { - if (GetInput().empty()) { - return false; +void VotincevDRadixMergeSortOMP::Merge(const uint32_t *src, uint32_t *dst, int32_t left, int32_t mid, int32_t right) { + int32_t i = left; + int32_t j = mid; + int32_t k = left; + while (i < mid && j < right) { + dst[k++] = (src[i] <= src[j]) ? src[i++] : src[j++]; } + while (i < mid) { + dst[k++] = src[i++]; + } + while (j < right) { + dst[k++] = src[j++]; + } +} - std::vector working_array = GetInput(); - auto n = static_cast(working_array.size()); +bool VotincevDRadixMergeSortOMP::RunImpl() { + const auto &input = GetInput(); + auto n = static_cast(input.size()); - int32_t min_val = working_array[0]; -#pragma omp parallel for reduction(min : min_val) default(none) shared(working_array, n) - for (int32_t i = 0; i < n; ++i) { - min_val = std::min(min_val, working_array[i]); - } + std::vector working_array(static_cast(n)); + int32_t min_val = input[0]; - if (min_val < 0) { -#pragma omp parallel for default(none) shared(working_array, n, min_val) - for (int32_t i = 0; i < n; ++i) { - working_array[i] -= min_val; - } +#pragma omp parallel for reduction(min : min_val) default(none) shared(n, input) + for (int32_t i = 0; i < n; ++i) { + min_val = std::min(input[i], min_val); } - int32_t max_val = working_array[0]; -#pragma omp parallel for reduction(max : max_val) default(none) shared(working_array, n) +#pragma omp parallel for default(none) shared(n, working_array, input, min_val) for (int32_t i = 0; i < n; ++i) { - max_val = std::max(max_val, working_array[i]); + working_array[static_cast(i)] = static_cast(input[i]) - static_cast(min_val); } - for (int32_t exp = 1; max_val / exp > 0; exp *= 10) { - SortByDigit(working_array, exp); - } + std::vector temp_buffer(static_cast(n)); - if (min_val < 0) { -#pragma omp parallel for default(none) shared(working_array, n, min_val) - for (int32_t i = 0; i < n; ++i) { - working_array[i] += min_val; +#pragma omp parallel default(none) shared(n, working_array, temp_buffer) + { + int tid = omp_get_thread_num(); + int n_threads = omp_get_num_threads(); + + int32_t items = n / n_threads; + int32_t rem = n % n_threads; + int32_t l = (tid * items) + std::min(tid, rem); + int32_t r = l + items + (tid < rem ? 1 : 0); + + if (l < r) { + LocalRadixSort(working_array.data() + l, working_array.data() + r); + } + + for (int32_t step = 1; step < n_threads; step *= 2) { +#pragma omp barrier + if ((tid % (2 * step) == 0) && (tid + step < n_threads)) { + int32_t m = ((tid + step) * items) + std::min(tid + step, rem); + int32_t next_tid = std::min(tid + (2 * step), n_threads); + int32_t next_r = (next_tid * items) + std::min(next_tid, rem); + + Merge(working_array.data(), temp_buffer.data(), l, m, next_r); + std::copy(temp_buffer.data() + l, temp_buffer.data() + next_r, working_array.data() + l); + } } } - GetOutput() = working_array; + std::vector result(static_cast(n)); +#pragma omp parallel for default(none) shared(n, result, working_array, min_val) + for (int32_t i = 0; i < n; ++i) { + result[static_cast(i)] = + static_cast(working_array[static_cast(i)] + static_cast(min_val)); + } + GetOutput() = std::move(result); return true; } diff --git a/tasks/votincev_d_radixmerge_sort/seq/src/ops_seq.cpp b/tasks/votincev_d_radixmerge_sort/seq/src/ops_seq.cpp index 85cca66ce..9c016cad9 100644 --- a/tasks/votincev_d_radixmerge_sort/seq/src/ops_seq.cpp +++ b/tasks/votincev_d_radixmerge_sort/seq/src/ops_seq.cpp @@ -1,8 +1,10 @@ #include "votincev_d_radixmerge_sort/seq/include/ops_seq.hpp" #include +#include #include #include +#include #include #include "votincev_d_radixmerge_sort/common/include/common.hpp" @@ -14,78 +16,73 @@ VotincevDRadixMergeSortSEQ::VotincevDRadixMergeSortSEQ(const InType &in) { GetInput() = in; } -// проверка входных данных bool VotincevDRadixMergeSortSEQ::ValidationImpl() { - // проверка: входной вектор не должен быть пустым return !GetInput().empty(); } -// препроцессинг bool VotincevDRadixMergeSortSEQ::PreProcessingImpl() { return true; } -// вспомогательный метод для распределения и слияния разрядов +// поразрядная сортировка void VotincevDRadixMergeSortSEQ::SortByDigit(std::vector &array, int32_t exp) { - std::vector> buckets(10); + size_t n = array.size(); + std::vector output(n); + std::array count{}; - // распределение элементов по корзинам - for (const auto &num : array) { - int32_t digit = (num / exp) % 10; - buckets[digit].push_back(num); + for (size_t i = 0; i < n; i++) { + int32_t digit = (array[i] / exp) % 10; + count.at(static_cast(digit))++; } - // простое слияние корзин обратно в рабочий массив - size_t index = 0; - for (int i = 0; i < 10; ++i) { - for (const auto &val : buckets[i]) { - array[index++] = val; - } - // очистка корзины для следующего разряда - buckets[i].clear(); + // префиксные суммы + for (size_t i = 1; i < 10; i++) { + count.at(i) += count.at(i - 1); } -} -// основной метод алгоритма -bool VotincevDRadixMergeSortSEQ::RunImpl() { - if (GetInput().empty()) { - return false; + // формирую выходной массив + for (int64_t i = static_cast(n) - 1; i >= 0; i--) { + auto idx = static_cast(i); + auto digit = static_cast((array.at(idx) / exp) % 10); + size_t pos = static_cast(count.at(digit)) - 1; + output.at(pos) = array.at(idx); + count.at(digit)--; } - // локальная копия данных для сортировки + array = std::move(output); +} + +bool VotincevDRadixMergeSortSEQ::RunImpl() { std::vector working_array = GetInput(); - // обработка отрицательных чисел - int32_t min_val = *std::ranges::min_element(working_array); + auto [min_it, max_it] = std::ranges::minmax_element(working_array); + int32_t min_val = *min_it; + int32_t max_val = *max_it; + // сдвиг в положительную область if (min_val < 0) { for (auto &num : working_array) { num -= min_val; } + max_val -= min_val; } - // ищем максимальное число для определения количества разрядов - int32_t max_val = *std::ranges::max_element(working_array); - - // цикл по разрядам (единицы, десятки, сотни...) - for (int32_t exp = 1; max_val / exp > 0; exp *= 10) { - SortByDigit(working_array, exp); + // цикл по разрядам + for (int64_t exp = 1; static_cast(max_val) / exp > 0; exp *= 10) { + SortByDigit(working_array, static_cast(exp)); } - // возвращаем значения к исходному диапазону + // возврат к исходному диапазону if (min_val < 0) { for (auto &num : working_array) { num += min_val; } } - // запись результата в выходные данные - GetOutput() = working_array; - + GetOutput() = std::move(working_array); return true; } -// постпроцессинг bool VotincevDRadixMergeSortSEQ::PostProcessingImpl() { return true; }