aca-tasks/task1/mergesort.h
2023-11-01 13:37:49 +01:00

193 lines
7.2 KiB
C++

#pragma once
#include <vector>
#include <algorithm>
#include <thread>
#include <mutex>
namespace algo {
class MergeSort_v1 {
private:
template<typename Iterator, typename Comparator>
static auto
merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start) -> void {
Iterator start_m = start;
Iterator begin = output_start;
Iterator start2 = middle + 1;
//merge from input until one half completes
while (start <= middle && start2 <= end) {
if (cmp(*start, *start2)) {
*output_start = *start;
start++;
} else {
*output_start = *start2;
start2++;
}
output_start++;
}
//try to finish first half
while (start <= middle) {
*output_start = *start;
start++;
output_start++;
}
while (start2 <= end) {
*output_start = *start2;
start2++;
output_start++;
}
const auto size = std::distance(start_m, end);
for (auto i = 0; i <= size; i++, start_m++, begin++) {
*start_m = *begin;
}
}
template<typename Container, typename Iterator, typename Comparator>
static auto
ms_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start) -> void {
Iterator mid = start;
Iterator begin = output_start;
if (std::distance(start, end) < 1) {
return;
} else {
//move mid iterator litterally to the mid
std::advance(mid, std::distance(start, end) / 2);
//sort the first half within an recursion
ms_split(output_vec, start, mid, cmp, output_start);
//move output iterator
std::advance(output_start, std::distance(start, mid + 1));
//sort the second half within a recursion
ms_split(output_vec, mid + 1, end, cmp, output_start);
//merge everything together starting from the complete beginning
merge(start, mid, end, cmp, begin);
}
}
public:
template<typename Iterator, typename Comparator>
static auto sort(Iterator start, Iterator end, Comparator cmp) -> void {
using valtype = typename std::iterator_traits<Iterator>::value_type;
std::vector<valtype> temporary_dataset(std::distance(start, end));
ms_split(temporary_dataset, start, end - 1, cmp, temporary_dataset.begin());
}
};
class MergeSort_v2 {
private:
template<typename Iterator, typename Comparator>
static auto
mt_merge() {
}
template<typename Iterator, typename Comparator>
static auto
merge(Iterator start, Iterator middle, Iterator end, Comparator cmp, Iterator output_start, std::recursive_mutex &dataset_guard) -> void {
Iterator start_m = start;
Iterator begin = output_start;
Iterator start2 = middle + 1;
//merge from input until one half completes
while (start <= middle && start2 <= end) {
if (cmp(*start, *start2)) {
*output_start = *start;
start++;
} else {
*output_start = *start2;
start2++;
}
output_start++;
}
//try to finish first half
while (start <= middle) {
*output_start = *start;
start++;
output_start++;
}
while (start2 <= end) {
*output_start = *start2;
start2++;
output_start++;
}
dataset_guard.lock();
const auto size = std::distance(start_m, end);
for (auto i = 0; i <= size; i++, start_m++, begin++) {
*start_m = *begin;
}
dataset_guard.unlock();
}
template<typename Container, typename Iterator, typename Comparator>
static auto ms_split(Container &output_vec, Iterator start, Iterator end, Comparator cmp, Iterator output_start,
int &nthreads, std::recursive_mutex &dataset_guard, std::mutex &depth_guard) -> void {
Iterator mid = start;
Iterator begin = output_start;
if (std::distance(start, end) < 1) {
//Quit on smalles list size (one element is always sorted)
return;
} else {
if (nthreads > 1) {
depth_guard.lock();
nthreads -= 2;
depth_guard.unlock();
//move mid iterator litterally to the mid
std::advance(mid, std::distance(start, end) / 2);
//sort the first half within an recursion
std::thread t1([&]() { ms_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard); });
//move output iteratoroutput_vec, start, mid, cmp, output_start
std::advance(output_start, std::distance(start, mid + 1));
//sort the second half within a recursion
std::thread t2([&]() { ms_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard); });
//merge everything together starting from the complete beginning
t1.join();
t2.join();
merge(start, mid, end, cmp, begin, dataset_guard);
} else {
//move mid iterator litterally to the mid
std::advance(mid, std::distance(start, end) / 2);
//sort the first half within an recursion
ms_split(output_vec, start, mid, cmp, output_start, nthreads, dataset_guard, depth_guard);
//move output iterator
std::advance(output_start, std::distance(start, mid + 1));
//sort the second half within a recursion
ms_split(output_vec, mid + 1, end, cmp, output_start, nthreads, dataset_guard, depth_guard);
//merge everything together starting from the complete beginning
merge(start, mid, end, cmp, begin, dataset_guard);
}
}
}
public:
template<typename Iterator, typename Comparator>
static auto sort(Iterator start, Iterator end, Comparator cmp, int nthreads) -> void {
using valtype = typename std::iterator_traits<Iterator>::value_type;
std::vector<valtype> temporary_dataset(std::distance(start, end));
std::recursive_mutex dataset_guard;
std::mutex depth_guard;
ms_split(temporary_dataset, start, end - 1, cmp, temporary_dataset.begin(), nthreads, dataset_guard, depth_guard);
}
};
}