Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tasks/votincev_d_radixmerge_sort/omp/include/ops_omp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ class VotincevDRadixMergeSortOMP : public BaseTask {
// ==============================
// мои дополнительные функции ===
static void SortByDigit(std::vector<int32_t> &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
125 changes: 88 additions & 37 deletions tasks/votincev_d_radixmerge_sort/omp/src/ops_omp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#include <omp.h>

#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <vector>

#include "votincev_d_radixmerge_sort/common/include/common.hpp"
Expand All @@ -24,63 +26,112 @@ bool VotincevDRadixMergeSortOMP::PreProcessingImpl() {
return true;
}

void VotincevDRadixMergeSortOMP::SortByDigit(std::vector<int32_t> &array, int32_t exp) {
std::vector<std::vector<int32_t>> 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<int32_t>(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<uint32_t> buffer(static_cast<size_t>(n));
uint32_t *src = begin;
uint32_t *dst = buffer.data();

for (int64_t exp = 1; (static_cast<int64_t>(max_val) / exp) > 0; exp *= 10) {
std::array<int32_t, 10> count{};

for (int32_t i = 0; i < n; ++i) {
count.at(static_cast<size_t>((src[i] / exp) % 10))++;
}
for (int32_t i = 1; i < 10; ++i) {
count.at(static_cast<size_t>(i)) += count.at(static_cast<size_t>(i - 1));
}
buckets[i].clear();
for (int32_t i = n - 1; i >= 0; --i) {
auto digit = static_cast<size_t>((src[i] / exp) % 10);

size_t target_idx = static_cast<size_t>(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<int32_t> working_array = GetInput();
auto n = static_cast<int32_t>(working_array.size());
bool VotincevDRadixMergeSortOMP::RunImpl() {
const auto &input = GetInput();
auto n = static_cast<int32_t>(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<uint32_t> working_array(static_cast<size_t>(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<size_t>(i)] = static_cast<uint32_t>(input[i]) - static_cast<uint32_t>(min_val);
}

for (int32_t exp = 1; max_val / exp > 0; exp *= 10) {
SortByDigit(working_array, exp);
}
std::vector<uint32_t> temp_buffer(static_cast<size_t>(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<int32_t> result(static_cast<size_t>(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<size_t>(i)] =
static_cast<int32_t>(working_array[static_cast<size_t>(i)] + static_cast<uint32_t>(min_val));
}

GetOutput() = std::move(result);
return true;
}

Expand Down
69 changes: 33 additions & 36 deletions tasks/votincev_d_radixmerge_sort/seq/src/ops_seq.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#include "votincev_d_radixmerge_sort/seq/include/ops_seq.hpp"

#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <vector>

#include "votincev_d_radixmerge_sort/common/include/common.hpp"
Expand All @@ -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<int32_t> &array, int32_t exp) {
std::vector<std::vector<int32_t>> buckets(10);
size_t n = array.size();
std::vector<int32_t> output(n);
std::array<int32_t, 10> 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<size_t>(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<int64_t>(n) - 1; i >= 0; i--) {
auto idx = static_cast<size_t>(i);
auto digit = static_cast<size_t>((array.at(idx) / exp) % 10);
size_t pos = static_cast<size_t>(count.at(digit)) - 1;
output.at(pos) = array.at(idx);
count.at(digit)--;
}

// локальная копия данных для сортировки
array = std::move(output);
}

bool VotincevDRadixMergeSortSEQ::RunImpl() {
std::vector<int32_t> 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<int64_t>(max_val) / exp > 0; exp *= 10) {
SortByDigit(working_array, static_cast<int32_t>(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;
}
Expand Down
Loading