From 731acb4c05c4219ccaf56f8a44cda2d41a54c04b Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Sun, 12 Apr 2026 13:50:42 +0300 Subject: [PATCH 1/8] omp optimization --- .../omp/include/ops_omp.hpp | 2 + .../omp/src/ops_omp.cpp | 129 +++++++++++++----- 2 files changed, 94 insertions(+), 37 deletions(-) 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..44550c57b 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(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..a96bcef1e 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp +++ b/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp @@ -3,12 +3,9 @@ #include #include -#include -#include +#include #include -#include "votincev_d_radixmerge_sort/common/include/common.hpp" - namespace votincev_d_radixmerge_sort { VotincevDRadixMergeSortOMP::VotincevDRadixMergeSortOMP(const InType &in) { @@ -24,63 +21,121 @@ bool VotincevDRadixMergeSortOMP::PreProcessingImpl() { return true; } -void VotincevDRadixMergeSortOMP::SortByDigit(std::vector &array, int32_t exp) { - std::vector> buckets(10); +void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) { + int32_t n = static_cast(end - begin); + if (n <= 1) { + return; + } - for (const auto &num : array) { - int32_t digit = (num / exp) % 10; - buckets[digit].push_back(num); + uint32_t max_val = begin[0]; + for (int32_t i = 1; i < n; ++i) { + if (begin[i] > max_val) { + max_val = begin[i]; + } } - size_t index = 0; - for (int i = 0; i < 10; ++i) { - for (const auto &val : buckets[i]) { - array[index++] = val; + std::vector buffer(n); + uint32_t *src = begin; + uint32_t *dst = buffer.data(); + + // int64_t для exp, чтобы избежать переполнения при exp * 10 + for (int64_t exp = 1; static_cast(max_val) / exp > 0; exp *= 10) { + int32_t count[10] = {0}; + + for (int32_t i = 0; i < n; ++i) { + count[(src[i] / exp) % 10]++; + } + for (int32_t i = 1; i < 10; ++i) { + count[i] += count[i - 1]; } - buckets[i].clear(); + for (int32_t i = n - 1; i >= 0; --i) { + uint32_t digit = (src[i] / exp) % 10; + dst[--count[digit]] = src[i]; + } + std::swap(src, dst); + } + + if (src != begin) { + std::copy(src, src + n, begin); + } +} + +void VotincevDRadixMergeSortOMP::Merge(uint32_t *src, uint32_t *dst, int32_t left, int32_t mid, int32_t right) { + int32_t i = left, j = mid, 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++]; } } bool VotincevDRadixMergeSortOMP::RunImpl() { - if (GetInput().empty()) { + const auto &input = GetInput(); + int32_t n = static_cast(input.size()); + if (n == 0) { return false; } - std::vector working_array = GetInput(); - auto n = static_cast(working_array.size()); + // uint32_t для работы с полным диапазоном int32_t без переполнений + std::vector working_array(n); + int32_t min_val = input[0]; - int32_t min_val = working_array[0]; -#pragma omp parallel for reduction(min : min_val) default(none) shared(working_array, n) +#pragma omp parallel for reduction(min : min_val) for (int32_t i = 0; i < n; ++i) { - min_val = std::min(min_val, working_array[i]); - } - - 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; + if (input[i] < min_val) { + min_val = input[i]; } } - 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 for (int32_t i = 0; i < n; ++i) { - max_val = std::max(max_val, working_array[i]); + working_array[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(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 + { + 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_r = (tid + 2 * step) * items + std::min(tid + 2 * step, rem); + if (next_r > n) { + next_r = n; + } + + 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(n); +#pragma omp parallel for + for (int32_t i = 0; i < n; ++i) { + result[i] = static_cast(working_array[i] + static_cast(min_val)); + } + GetOutput() = std::move(result); return true; } From 17405a952d09d740ffbc09e857f198719ce0bb28 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Sun, 12 Apr 2026 15:51:35 +0300 Subject: [PATCH 2/8] clang-tidy fix1 --- .../omp/src/ops_omp.cpp | 79 ++++++++----------- 1 file changed, 35 insertions(+), 44 deletions(-) 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 a96bcef1e..e8bed1432 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp +++ b/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp @@ -3,9 +3,13 @@ #include #include -#include +#include +#include +#include #include +#include "votincev_d_radixmerge_sort/common/include/common.hpp" + namespace votincev_d_radixmerge_sort { VotincevDRadixMergeSortOMP::VotincevDRadixMergeSortOMP(const InType &in) { @@ -21,36 +25,30 @@ bool VotincevDRadixMergeSortOMP::PreProcessingImpl() { return true; } -void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) { - int32_t n = static_cast(end - begin); +void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, const uint32_t *end) { + auto n = static_cast(end - begin); if (n <= 1) { return; } - uint32_t max_val = begin[0]; - for (int32_t i = 1; i < n; ++i) { - if (begin[i] > max_val) { - max_val = begin[i]; - } - } + uint32_t max_val = *std::max_element(begin, end); - std::vector buffer(n); + std::vector buffer(static_cast(n)); uint32_t *src = begin; uint32_t *dst = buffer.data(); - // int64_t для exp, чтобы избежать переполнения при exp * 10 - for (int64_t exp = 1; static_cast(max_val) / exp > 0; exp *= 10) { - int32_t count[10] = {0}; + 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[(src[i] / exp) % 10]++; + count[static_cast((src[i] / exp) % 10)]++; } for (int32_t i = 1; i < 10; ++i) { - count[i] += count[i - 1]; + count[static_cast(i)] += count[static_cast(i - 1)]; } for (int32_t i = n - 1; i >= 0; --i) { uint32_t digit = (src[i] / exp) % 10; - dst[--count[digit]] = src[i]; + dst[--count[static_cast(digit)]] = src[i]; } std::swap(src, dst); } @@ -60,8 +58,10 @@ void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) } } -void VotincevDRadixMergeSortOMP::Merge(uint32_t *src, uint32_t *dst, int32_t left, int32_t mid, int32_t right) { - int32_t i = left, j = mid, k = left; +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++]; } @@ -75,53 +75,43 @@ void VotincevDRadixMergeSortOMP::Merge(uint32_t *src, uint32_t *dst, int32_t lef bool VotincevDRadixMergeSortOMP::RunImpl() { const auto &input = GetInput(); - int32_t n = static_cast(input.size()); - if (n == 0) { - return false; - } + auto n = static_cast(input.size()); - // uint32_t для работы с полным диапазоном int32_t без переполнений - std::vector working_array(n); + std::vector working_array(static_cast(n)); int32_t min_val = input[0]; -#pragma omp parallel for reduction(min : min_val) +#pragma omp parallel for reduction(min : min_val) default(none) shared(n, input) for (int32_t i = 0; i < n; ++i) { - if (input[i] < min_val) { - min_val = input[i]; - } + min_val = std::min(input[i], min_val); } -#pragma omp parallel for +#pragma omp parallel for default(none) shared(n, working_array, input, min_val) for (int32_t i = 0; i < n; ++i) { - working_array[i] = static_cast(input[i]) - static_cast(min_val); + working_array[static_cast(i)] = static_cast(input[i]) - static_cast(min_val); } - std::vector temp_buffer(n); + std::vector temp_buffer(static_cast(n)); -#pragma omp parallel +#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 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_r = (tid + 2 * step) * items + std::min(tid + 2 * step, rem); - if (next_r > n) { - next_r = n; - } + if ((tid % (2 * step) == 0) && (tid + step < n_threads)) { + int32_t m = ((tid + step) * items) + std::min(tid + step, rem); + int32_t next_r = ((tid + 2 * step) * items) + std::min(tid + 2 * step, rem); + next_r = std::min(next_r, n); 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); @@ -129,10 +119,11 @@ bool VotincevDRadixMergeSortOMP::RunImpl() { } } - std::vector result(n); -#pragma omp parallel for + 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[i] = static_cast(working_array[i] + static_cast(min_val)); + result[static_cast(i)] = + static_cast(working_array[static_cast(i)] + static_cast(min_val)); } GetOutput() = std::move(result); From cb2b8acb4840153130dcf7de3d3248a8191444ff Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Mon, 13 Apr 2026 18:23:29 +0300 Subject: [PATCH 3/8] fix --- tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 e8bed1432..ce8bb7fff 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp +++ b/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp @@ -25,7 +25,7 @@ bool VotincevDRadixMergeSortOMP::PreProcessingImpl() { return true; } -void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, const uint32_t *end) { +void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) { auto n = static_cast(end - begin); if (n <= 1) { return; @@ -58,7 +58,7 @@ void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, const uint32_t } } -void VotincevDRadixMergeSortOMP::Merge(const uint32_t *src, uint32_t *dst, int32_t left, int32_t mid, int32_t right) { +void VotincevDRadixMergeSortOMP::Merge(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; From 9d53531b2d57b19ec0f5243b3f75add22f87e418 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Mon, 13 Apr 2026 19:31:58 +0300 Subject: [PATCH 4/8] clang-tidy fix 11 --- .../omp/include/ops_omp.hpp | 2 +- tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) 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 44550c57b..559533ddb 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/include/ops_omp.hpp +++ b/tasks/votincev_d_radixmerge_sort/omp/include/ops_omp.hpp @@ -25,6 +25,6 @@ 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(uint32_t *src, uint32_t *dst, int32_t left, int32_t mid, int32_t right); + 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 ce8bb7fff..69d504596 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp +++ b/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -41,14 +42,15 @@ void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) std::array count{}; for (int32_t i = 0; i < n; ++i) { - count[static_cast((src[i] / exp) % 10)]++; + count.at(static_cast((src[i] / exp) % 10))++; } for (int32_t i = 1; i < 10; ++i) { - count[static_cast(i)] += count[static_cast(i - 1)]; + count.at(static_cast(i)) += count.at(static_cast(i - 1)); } for (int32_t i = n - 1; i >= 0; --i) { uint32_t digit = (src[i] / exp) % 10; - dst[--count[static_cast(digit)]] = src[i]; + dst.at(count.at(static_cast(digit))) = src[i]; + count.at(static_cast(digit))--; } std::swap(src, dst); } @@ -58,7 +60,7 @@ void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) } } -void VotincevDRadixMergeSortOMP::Merge(uint32_t *src, uint32_t *dst, int32_t left, int32_t mid, int32_t right) { +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; @@ -110,7 +112,7 @@ bool VotincevDRadixMergeSortOMP::RunImpl() { #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_r = ((tid + 2 * step) * items) + std::min(tid + 2 * step, rem); + int32_t next_r = ((tid + (2 * step)) * items) + std::min(tid + (2 * step), rem); next_r = std::min(next_r, n); Merge(working_array.data(), temp_buffer.data(), l, m, next_r); From 6e4caf3f86e5d7697558eb6bef3958d8580a88fc Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Mon, 13 Apr 2026 19:53:19 +0300 Subject: [PATCH 5/8] clang-tidy fix24234 --- tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 69d504596..ddf6e8e08 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp +++ b/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp @@ -49,7 +49,7 @@ void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) } for (int32_t i = n - 1; i >= 0; --i) { uint32_t digit = (src[i] / exp) % 10; - dst.at(count.at(static_cast(digit))) = src[i]; + dst[count.at(static_cast(digit))] = src[i]; count.at(static_cast(digit))--; } std::swap(src, dst); From 10623f42394074647b9051ceebe1e0bdaaf2b1d3 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Wed, 15 Apr 2026 19:19:16 +0300 Subject: [PATCH 6/8] build + clang fix --- .../votincev_d_radixmerge_sort/omp/src/ops_omp.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) 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 ddf6e8e08..2f2e46d75 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp +++ b/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp @@ -48,9 +48,12 @@ void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) count.at(static_cast(i)) += count.at(static_cast(i - 1)); } for (int32_t i = n - 1; i >= 0; --i) { - uint32_t digit = (src[i] / exp) % 10; - dst[count.at(static_cast(digit))] = src[i]; - count.at(static_cast(digit))--; + size_t 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); } @@ -112,8 +115,8 @@ bool VotincevDRadixMergeSortOMP::RunImpl() { #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_r = ((tid + (2 * step)) * items) + std::min(tid + (2 * step), rem); - next_r = std::min(next_r, n); + 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); From b9d8a0f159dae3a5cfbdad15bd44ab7857652a97 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Wed, 15 Apr 2026 20:17:25 +0300 Subject: [PATCH 7/8] fix --- tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2f2e46d75..8fdd0ee61 100644 --- a/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp +++ b/tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp @@ -48,7 +48,7 @@ void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) count.at(static_cast(i)) += count.at(static_cast(i - 1)); } for (int32_t i = n - 1; i >= 0; --i) { - size_t digit = static_cast((src[i] / exp) % 10); + auto digit = static_cast((src[i] / exp) % 10); size_t target_idx = static_cast(count.at(digit)) - 1; dst[target_idx] = src[i]; From 9ed579b6a7b776a4d0076a3198d62c00c9808464 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Thu, 16 Apr 2026 16:52:27 +0300 Subject: [PATCH 8/8] seq change to avoid conflict --- .../seq/src/ops_seq.cpp | 69 +++++++++---------- 1 file changed, 33 insertions(+), 36 deletions(-) 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; }