From 741f85655315a922b6580af7106fee5d97c03080 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Sun, 12 Apr 2026 13:53:38 +0300 Subject: [PATCH 1/7] tbb added --- .../tbb/include/ops_tbb.hpp | 30 ++++ .../tbb/src/ops_tbb.cpp | 137 ++++++++++++++++++ .../tests/functional/main.cpp | 4 +- .../tests/performance/main.cpp | 6 +- 4 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp create mode 100644 tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp diff --git a/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp b/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp new file mode 100644 index 000000000..6472a3bc0 --- /dev/null +++ b/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" +#include "votincev_d_radixmerge_sort/common/include/common.hpp" + +namespace votincev_d_radixmerge_sort { + +class VotincevDRadixMergeSortTBB : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kTBB; + } + explicit VotincevDRadixMergeSortTBB(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + + // ============================== + // мои дополнительные функции === + static void LocalRadixSort(uint32_t *begin, uint32_t *end); + static void Merge(uint32_t *data, int32_t left, int32_t mid, int32_t right, uint32_t *temp); + static void ParallelRadixMergeSort(uint32_t *data, int32_t left, int32_t right, uint32_t *temp); +}; +} // namespace votincev_d_radixmerge_sort diff --git a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp new file mode 100644 index 000000000..f1c9a9b81 --- /dev/null +++ b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp @@ -0,0 +1,137 @@ +#include "votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp" + +#include + +#include +#include + +#include "votincev_d_radixmerge_sort/common/include/common.hpp" + +namespace votincev_d_radixmerge_sort { + +VotincevDRadixMergeSortTBB::VotincevDRadixMergeSortTBB(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; +} + +bool VotincevDRadixMergeSortTBB::ValidationImpl() { + return !GetInput().empty(); +} + +bool VotincevDRadixMergeSortTBB::PreProcessingImpl() { + return true; +} + +// поразрядная сортировка для локальных блоков +void VotincevDRadixMergeSortTBB::LocalRadixSort(uint32_t *begin, uint32_t *end) { + int32_t 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]; + } + } + + 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]; + } + 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 VotincevDRadixMergeSortTBB::Merge(uint32_t *data, int32_t left, int32_t mid, int32_t right, uint32_t *temp) { + int32_t i = left, j = mid, k = left; + while (i < mid && j < right) { + temp[k++] = (data[i] <= data[j]) ? data[i++] : data[j++]; + } + while (i < mid) { + temp[k++] = data[i++]; + } + while (j < right) { + temp[k++] = data[j++]; + } + + std::copy(temp + left, temp + right, data + left); +} + +// параллельная сортировка слиянием(сортировка + слияние) +void VotincevDRadixMergeSortTBB::ParallelRadixMergeSort(uint32_t *data, int32_t left, int32_t right, uint32_t *temp) { + const int32_t GRAIN_SIZE = 4096; // порог для перехода на последовательную сортировку + + if (right - left <= GRAIN_SIZE) { + LocalRadixSort(data + left, data + right); + return; + } + + int32_t mid = left + (right - left) / 2; + + // рекурсивно запускаются две задачи в параллель + tbb::parallel_invoke([&] { ParallelRadixMergeSort(data, left, mid, temp); }, + [&] { ParallelRadixMergeSort(data, mid, right, temp); }); + + // слияние результатов + Merge(data, left, mid, right, temp); +} + +bool VotincevDRadixMergeSortTBB::RunImpl() { + const auto &input = GetInput(); + int32_t n = static_cast(input.size()); + + // поиск минимума + int32_t min_val = tbb::parallel_reduce(tbb::blocked_range(0, n), input[0], + [&](const tbb::blocked_range &r, int32_t local_min) { + for (int32_t i = r.begin(); i < r.end(); ++i) { + if (input[i] < local_min) { + local_min = input[i]; + } + } + return local_min; + }, [](int32_t a, int32_t b) { return std::min(a, b); }); + + // приведение к положительным uint32 + std::vector working_array(n); + tbb::parallel_for( + 0, n, [&](int32_t i) { working_array[i] = static_cast(input[i]) - static_cast(min_val); }); + + // параллельная сортировка со слиянием + std::vector temp_buffer(n); + ParallelRadixMergeSort(working_array.data(), 0, n, temp_buffer.data()); + + // восстановление исходных значений + std::vector result(n); + tbb::parallel_for( + 0, n, [&](int32_t i) { result[i] = static_cast(working_array[i] + static_cast(min_val)); }); + + GetOutput() = std::move(result); + return true; +} + +bool VotincevDRadixMergeSortTBB::PostProcessingImpl() { + return true; +} + +} // namespace votincev_d_radixmerge_sort diff --git a/tasks/votincev_d_radixmerge_sort/tests/functional/main.cpp b/tasks/votincev_d_radixmerge_sort/tests/functional/main.cpp index 97b441e7d..7a1560971 100644 --- a/tasks/votincev_d_radixmerge_sort/tests/functional/main.cpp +++ b/tasks/votincev_d_radixmerge_sort/tests/functional/main.cpp @@ -14,6 +14,7 @@ #include "votincev_d_radixmerge_sort/common/include/common.hpp" #include "votincev_d_radixmerge_sort/omp/include/ops_omp.hpp" #include "votincev_d_radixmerge_sort/seq/include/ops_seq.hpp" +#include "votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp" namespace votincev_d_radixmerge_sort { @@ -78,7 +79,8 @@ const std::array kTestParam = {"test1", "test2", "test3", "test4", const auto kTestTasksList = std::tuple_cat( ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_votincev_d_radixmerge_sort), - ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_votincev_d_radixmerge_sort)); + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_votincev_d_radixmerge_sort), + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_votincev_d_radixmerge_sort)); const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); diff --git a/tasks/votincev_d_radixmerge_sort/tests/performance/main.cpp b/tasks/votincev_d_radixmerge_sort/tests/performance/main.cpp index 535f0ec08..a71b843f0 100644 --- a/tasks/votincev_d_radixmerge_sort/tests/performance/main.cpp +++ b/tasks/votincev_d_radixmerge_sort/tests/performance/main.cpp @@ -8,6 +8,7 @@ #include "votincev_d_radixmerge_sort/common/include/common.hpp" #include "votincev_d_radixmerge_sort/omp/include/ops_omp.hpp" #include "votincev_d_radixmerge_sort/seq/include/ops_seq.hpp" +#include "votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp" namespace votincev_d_radixmerge_sort { @@ -45,8 +46,9 @@ class VotincevDRadixMergeSortRunPerfTestsThreads : public ppc::util::BaseRunPerf }; namespace { -const auto kAllPerfTasks = ppc::util::MakeAllPerfTasks( - PPC_SETTINGS_votincev_d_radixmerge_sort); +const auto kAllPerfTasks = + ppc::util::MakeAllPerfTasks(PPC_SETTINGS_votincev_d_radixmerge_sort); const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); const auto kPerfTestName = VotincevDRadixMergeSortRunPerfTestsThreads::CustomPerfTestName; From e948b676ff4b1720084588af0762f6af98bae2e5 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Sun, 12 Apr 2026 15:55:25 +0300 Subject: [PATCH 2/7] clang-tidy fix1 --- .../tbb/include/ops_tbb.hpp | 1 - .../tbb/src/ops_tbb.cpp | 67 ++++++++++--------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp b/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp index 6472a3bc0..bff0b365b 100644 --- a/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp +++ b/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include "task/include/task.hpp" #include "votincev_d_radixmerge_sort/common/include/common.hpp" diff --git a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp index f1c9a9b81..9d1f11465 100644 --- a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp +++ b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp @@ -3,6 +3,9 @@ #include #include +#include +#include +#include #include #include "votincev_d_radixmerge_sort/common/include/common.hpp" @@ -23,36 +26,34 @@ bool VotincevDRadixMergeSortTBB::PreProcessingImpl() { } // поразрядная сортировка для локальных блоков -void VotincevDRadixMergeSortTBB::LocalRadixSort(uint32_t *begin, uint32_t *end) { - int32_t n = static_cast(end - begin); +void VotincevDRadixMergeSortTBB::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]; - } + max_val = std::max(begin[static_cast(i)], max_val); } - 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[static_cast(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]; + uint32_t digit = (src[static_cast(i)] / exp) % 10; + dst[--count[static_cast(digit)]] = src[static_cast(i)]; } std::swap(src, dst); } @@ -64,15 +65,19 @@ void VotincevDRadixMergeSortTBB::LocalRadixSort(uint32_t *begin, uint32_t *end) // слияние двух отсортированных участков void VotincevDRadixMergeSortTBB::Merge(uint32_t *data, int32_t left, int32_t mid, int32_t right, uint32_t *temp) { - int32_t i = left, j = mid, k = left; + int32_t i = left; + int32_t j = mid; + int32_t k = left; while (i < mid && j < right) { - temp[k++] = (data[i] <= data[j]) ? data[i++] : data[j++]; + temp[static_cast(k++)] = (data[static_cast(i)] <= data[static_cast(j)]) + ? data[static_cast(i++)] + : data[static_cast(j++)]; } while (i < mid) { - temp[k++] = data[i++]; + temp[static_cast(k++)] = data[static_cast(i++)]; } while (j < right) { - temp[k++] = data[j++]; + temp[static_cast(k++)] = data[static_cast(j++)]; } std::copy(temp + left, temp + right, data + left); @@ -80,14 +85,14 @@ void VotincevDRadixMergeSortTBB::Merge(uint32_t *data, int32_t left, int32_t mid // параллельная сортировка слиянием(сортировка + слияние) void VotincevDRadixMergeSortTBB::ParallelRadixMergeSort(uint32_t *data, int32_t left, int32_t right, uint32_t *temp) { - const int32_t GRAIN_SIZE = 4096; // порог для перехода на последовательную сортировку + const int32_t grain_size = 4096; // порог для перехода на последовательную сортировку - if (right - left <= GRAIN_SIZE) { + if (right - left <= grain_size) { LocalRadixSort(data + left, data + right); return; } - int32_t mid = left + (right - left) / 2; + int32_t mid = left + ((right - left) / 2); // рекурсивно запускаются две задачи в параллель tbb::parallel_invoke([&] { ParallelRadixMergeSort(data, left, mid, temp); }, @@ -99,32 +104,34 @@ void VotincevDRadixMergeSortTBB::ParallelRadixMergeSort(uint32_t *data, int32_t bool VotincevDRadixMergeSortTBB::RunImpl() { const auto &input = GetInput(); - int32_t n = static_cast(input.size()); + auto n = static_cast(input.size()); // поиск минимума int32_t min_val = tbb::parallel_reduce(tbb::blocked_range(0, n), input[0], [&](const tbb::blocked_range &r, int32_t local_min) { for (int32_t i = r.begin(); i < r.end(); ++i) { - if (input[i] < local_min) { - local_min = input[i]; - } + local_min = std::min(input[static_cast(i)], local_min); } return local_min; }, [](int32_t a, int32_t b) { return std::min(a, b); }); // приведение к положительным uint32 - std::vector working_array(n); - tbb::parallel_for( - 0, n, [&](int32_t i) { working_array[i] = static_cast(input[i]) - static_cast(min_val); }); + std::vector working_array(static_cast(n)); + tbb::parallel_for(0, n, [&](int32_t i) { + working_array[static_cast(i)] = + static_cast(input[static_cast(i)]) - static_cast(min_val); + }); // параллельная сортировка со слиянием - std::vector temp_buffer(n); + std::vector temp_buffer(static_cast(n)); ParallelRadixMergeSort(working_array.data(), 0, n, temp_buffer.data()); // восстановление исходных значений - std::vector result(n); - tbb::parallel_for( - 0, n, [&](int32_t i) { result[i] = static_cast(working_array[i] + static_cast(min_val)); }); + std::vector result(static_cast(n)); + tbb::parallel_for(0, n, [&](int32_t i) { + result[static_cast(i)] = + static_cast(working_array[static_cast(i)] + static_cast(min_val)); + }); GetOutput() = std::move(result); return true; From d893122c6c6b4a7735c547a469b8b1efdfa9d53f Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Mon, 13 Apr 2026 18:20:53 +0300 Subject: [PATCH 3/7] clang-tidy fix2 --- tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp index 9d1f11465..9a11af4fe 100644 --- a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp +++ b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp @@ -26,7 +26,7 @@ bool VotincevDRadixMergeSortTBB::PreProcessingImpl() { } // поразрядная сортировка для локальных блоков -void VotincevDRadixMergeSortTBB::LocalRadixSort(uint32_t *begin, const uint32_t *end) { +void VotincevDRadixMergeSortTBB::LocalRadixSort(uint32_t *begin, uint32_t *end) { auto n = static_cast(end - begin); if (n <= 1) { return; From a70c14ce524d20fab063da65318396e59afb97ab Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Mon, 13 Apr 2026 19:50:55 +0300 Subject: [PATCH 4/7] clang-tidy fix241 --- .../tbb/include/ops_tbb.hpp | 2 +- .../tbb/src/ops_tbb.cpp | 29 +++++++------------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp b/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp index bff0b365b..242e2ff09 100644 --- a/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp +++ b/tasks/votincev_d_radixmerge_sort/tbb/include/ops_tbb.hpp @@ -23,7 +23,7 @@ class VotincevDRadixMergeSortTBB : public BaseTask { // ============================== // мои дополнительные функции === static void LocalRadixSort(uint32_t *begin, uint32_t *end); - static void Merge(uint32_t *data, int32_t left, int32_t mid, int32_t right, uint32_t *temp); + static void Merge(const uint32_t *src, uint32_t *dst, int32_t left, int32_t mid, int32_t right); static void ParallelRadixMergeSort(uint32_t *data, int32_t left, int32_t right, uint32_t *temp); }; } // namespace votincev_d_radixmerge_sort diff --git a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp index 9a11af4fe..a9380de5f 100644 --- a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp +++ b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp @@ -26,34 +26,31 @@ bool VotincevDRadixMergeSortTBB::PreProcessingImpl() { } // поразрядная сортировка для локальных блоков -void VotincevDRadixMergeSortTBB::LocalRadixSort(uint32_t *begin, uint32_t *end) { +void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, 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) { - max_val = std::max(begin[static_cast(i)], max_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(); - // int64_t для exp, чтобы избежать переполнения при exp * 10 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[static_cast((src[static_cast(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[static_cast(i)] / exp) % 10; - dst[--count[static_cast(digit)]] = src[static_cast(i)]; + uint32_t digit = (src[i] / exp) % 10; + dst.at(count.at(static_cast(digit))) = src[i]; + count.at(static_cast(digit))--; } std::swap(src, dst); } @@ -64,23 +61,19 @@ void VotincevDRadixMergeSortTBB::LocalRadixSort(uint32_t *begin, uint32_t *end) } // слияние двух отсортированных участков -void VotincevDRadixMergeSortTBB::Merge(uint32_t *data, int32_t left, int32_t mid, int32_t right, uint32_t *temp) { +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) { - temp[static_cast(k++)] = (data[static_cast(i)] <= data[static_cast(j)]) - ? data[static_cast(i++)] - : data[static_cast(j++)]; + dst[k++] = (src[i] <= src[j]) ? src[i++] : src[j++]; } while (i < mid) { - temp[static_cast(k++)] = data[static_cast(i++)]; + dst[k++] = src[i++]; } while (j < right) { - temp[static_cast(k++)] = data[static_cast(j++)]; + dst[k++] = src[j++]; } - - std::copy(temp + left, temp + right, data + left); } // параллельная сортировка слиянием(сортировка + слияние) From ddf126a49912f9cc6e68cc28b4de28a8c28df711 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Wed, 15 Apr 2026 20:19:20 +0300 Subject: [PATCH 5/7] fix --- .../tbb/src/ops_tbb.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp index a9380de5f..13c8f5156 100644 --- a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp +++ b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp @@ -26,7 +26,7 @@ bool VotincevDRadixMergeSortTBB::PreProcessingImpl() { } // поразрядная сортировка для локальных блоков -void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) { +void VotincevDRadixMergeSortTBB::LocalRadixSort(uint32_t *begin, uint32_t *end) { auto n = static_cast(end - begin); if (n <= 1) { return; @@ -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.at(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); } @@ -61,7 +64,7 @@ void VotincevDRadixMergeSortOMP::LocalRadixSort(uint32_t *begin, uint32_t *end) } // слияние двух отсортированных участков -void VotincevDRadixMergeSortOMP::Merge(const uint32_t *src, uint32_t *dst, int32_t left, int32_t mid, int32_t right) { +void VotincevDRadixMergeSortTBB::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; @@ -92,7 +95,10 @@ void VotincevDRadixMergeSortTBB::ParallelRadixMergeSort(uint32_t *data, int32_t [&] { ParallelRadixMergeSort(data, mid, right, temp); }); // слияние результатов - Merge(data, left, mid, right, temp); + Merge(data, temp, left, mid, right); + + // копируем в основной массив + std::copy(temp + left, temp + right, data + left); } bool VotincevDRadixMergeSortTBB::RunImpl() { From 0e8ceb7326ade058b95ba96e8b358d4bb12c9b54 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Wed, 15 Apr 2026 21:04:56 +0300 Subject: [PATCH 6/7] clang-tidy fix --- tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp | 3 ++- tasks/votincev_d_radixmerge_sort/tests/performance/main.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp index 13c8f5156..69f5f95d2 100644 --- a/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp +++ b/tasks/votincev_d_radixmerge_sort/tbb/src/ops_tbb.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,7 @@ void VotincevDRadixMergeSortTBB::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]; diff --git a/tasks/votincev_d_radixmerge_sort/tests/performance/main.cpp b/tasks/votincev_d_radixmerge_sort/tests/performance/main.cpp index a71b843f0..fae17ad8c 100644 --- a/tasks/votincev_d_radixmerge_sort/tests/performance/main.cpp +++ b/tasks/votincev_d_radixmerge_sort/tests/performance/main.cpp @@ -48,7 +48,7 @@ class VotincevDRadixMergeSortRunPerfTestsThreads : public ppc::util::BaseRunPerf namespace { const auto kAllPerfTasks = ppc::util::MakeAllPerfTasks(PPC_SETTINGS_votincev_d_radixmerge_sort); + VotincevDRadixMergeSortTBB>(PPC_SETTINGS_votincev_d_radixmerge_sort); const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); const auto kPerfTestName = VotincevDRadixMergeSortRunPerfTestsThreads::CustomPerfTestName; From dadf10ce1bc02ce3501f479501fdeb58bb503a05 Mon Sep 17 00:00:00 2001 From: DimaVotincev Date: Thu, 16 Apr 2026 16:58:29 +0300 Subject: [PATCH 7/7] seq+omp pull'ed to resolve conflicts --- .../omp/include/ops_omp.hpp | 2 + .../omp/src/ops_omp.cpp | 125 ++++++++++++------ .../seq/src/ops_seq.cpp | 69 +++++----- 3 files changed, 123 insertions(+), 73 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..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; }