aca-tasks/task2/include/quicksort_mt.h

80 lines
2.4 KiB
C
Raw Normal View History

2023-12-05 09:49:07 +00:00
#include <vector>
#include <span>
#include <thread>
#include <mutex>
#include <functional>
2023-12-05 21:36:06 +00:00
#include <assert.h>
2023-12-05 09:49:07 +00:00
template<typename T>
class QuickSorterMT {
public:
template<typename C>
QuickSorterMT(C cmp, int max_depth) : cmp(cmp), max_depth(max_depth) {
static_assert(std::is_same<std::invoke_result_t<C, T, T>, bool>(), "C must be a function that returns a bool");
}
auto sort(std::vector<T> &data) -> void {
std::span<T> sortable(data);
qsort(sortable, 0, max_depth);
}
private:
auto parition(std::span<T> &data) -> std::pair<std::span<T>, std::span<T>> {
2023-12-05 09:57:17 +00:00
auto pivot = data.begin();
std::advance(pivot, std::distance(data.begin(), data.end()) / 2);
2023-12-05 09:49:07 +00:00
2023-12-05 09:57:17 +00:00
auto lefti = data.begin();
2023-12-05 19:18:23 +00:00
auto righti = data.end() - 1;
2023-12-05 09:49:07 +00:00
while (1) {
2023-12-05 19:18:23 +00:00
for (; cmp((*lefti), (*pivot)); lefti++);
for (; !cmp((*righti), (*pivot)); righti--);
2023-12-05 09:49:07 +00:00
if (lefti >= righti) {
break;
}
2023-12-05 19:18:23 +00:00
std::swap(*lefti, *righti);
2023-12-05 09:49:07 +00:00
}
2023-12-05 20:54:43 +00:00
return {std::span<T>(data.begin(), pivot), std::span<T>(pivot, data.end())};
2023-12-05 09:49:07 +00:00
}
auto qsort(std::span<T> &data, int depth, const int &mdepth) -> void {
if (std::distance(data.begin(), data.end()) <= 1) {
return;
} else if (std::distance(data.begin(), data.end()) == 2) {
if (cmp(data[1], data[0])) {
std::swap(data[0], data[1]);
return;
}
}
2023-12-05 21:36:06 +00:00
auto pivot = *std::next(data.begin(), std::distance(data.begin(), data.end()) / 2);
2023-12-05 20:54:43 +00:00
auto m1 = std::partition(data.begin(), data.end(), [pivot, this](const auto &em) {
2023-12-05 21:39:03 +00:00
return this->cmp(pivot, em);
2023-12-05 20:54:43 +00:00
});
auto m2 = std::partition(m1, data.end(), [pivot, this](const auto &em) {
return !(this->cmp(em, pivot));
});
auto left = data.subspan(0, m1 - data.begin());
2023-12-05 21:36:06 +00:00
auto right = data.subspan(m2 - data.begin());
2023-12-05 09:49:07 +00:00
if (depth < mdepth) {
std::thread left_thread([&]() { qsort(left, depth + 1, mdepth); });
std::thread right_thread([&]() { qsort(right, depth + 1, mdepth); });
left_thread.join();
right_thread.join();
} else {
qsort(left, depth + 1, mdepth);
qsort(right, depth + 1, mdepth);
}
}
std::function<bool(T, T)> cmp;
const int max_depth;
};