Added comments in mergesort algorithm
This commit is contained in:
parent
af34983a46
commit
edde2e75fb
@ -4,22 +4,30 @@
|
||||
#include <mutex>
|
||||
#include <functional>
|
||||
|
||||
// General purpose mergesorter with multi threading support by Robin Dietzel <robin.dietzel@iem.thm.de>
|
||||
template<typename T>
|
||||
class MergeSorterMT {
|
||||
|
||||
public:
|
||||
template<typename C>
|
||||
MergeSorterMT(C cmp, int max_depth) : cmp(cmp), max_depth(max_depth) {
|
||||
// Assert that cmp is a function that returns bool and takes two arguments of type T
|
||||
static_assert(std::is_same<std::invoke_result_t<C, T, T>, bool>(), "C must be a function that returns a bool");
|
||||
}
|
||||
|
||||
// Start sorting process
|
||||
auto sort(std::vector<T> &data) -> void {
|
||||
// Create span: like a 'view' on the vector -> no unnecessary copies are made when subdividing sorting problem
|
||||
std::span<T> sortable(data);
|
||||
split(sortable, 0, max_depth);
|
||||
}
|
||||
|
||||
private:
|
||||
// Merge function that merges left & right span into the output span
|
||||
// No exclusive access on output is necessary (e.g. via mutex) because all parallel threads work on different parts of output
|
||||
auto merge(std::span<T> &output, std::span<T> left, std::span<T> right) -> void {
|
||||
// Create buffer, here we need a temporary container where we copy values to, because left and right are a view on parts
|
||||
// of output
|
||||
std::vector<T> buf;
|
||||
buf.reserve(left.size() + right.size());
|
||||
|
||||
@ -27,6 +35,7 @@ private:
|
||||
auto r = right.begin();
|
||||
auto o = buf.begin();
|
||||
|
||||
// Insert from pre sorted half's
|
||||
while (l < left.end() && r < right.end()) {
|
||||
if (cmp(*l, *r)) {
|
||||
buf.insert(o, *l);
|
||||
@ -37,52 +46,72 @@ private:
|
||||
}
|
||||
o++;
|
||||
}
|
||||
|
||||
// Fill up with rest of left values
|
||||
while (l < left.end()) {
|
||||
buf.insert(o, *l);
|
||||
o++;
|
||||
l++;
|
||||
}
|
||||
|
||||
// Fill up with rest of right values
|
||||
while (r < right.end()) {
|
||||
buf.insert(o, *r);
|
||||
o++;
|
||||
r++;
|
||||
}
|
||||
|
||||
// Completely move buffer to output
|
||||
// IMPORTANT: left and right are still a view on the splitted output, that is now sorted
|
||||
std::move(buf.begin(), buf.end(), output.begin());
|
||||
}
|
||||
|
||||
// Splitup function
|
||||
auto split(std::span<T> &data, int depth, const int &mdepth) -> void {
|
||||
|
||||
if (std::distance(data.begin(), data.end()) <= 1) {
|
||||
// Quit if only one element 'insortable'
|
||||
return;
|
||||
} else if (std::distance(data.begin(), data.end()) == 2) {
|
||||
// Swap two values dependant on size for small speedup (no call to further split must be made)
|
||||
if(cmp(data[1], data[0])) {
|
||||
std::swap(data[0], data[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine mid of data
|
||||
auto mid = data.begin();
|
||||
std::advance(mid, std::distance(data.begin(), data.end()) / 2);
|
||||
|
||||
// Generate left and right view on data (no copies are made here)
|
||||
std::span<T> left(data.begin(), mid);
|
||||
std::span<T> right(mid, data.end());
|
||||
|
||||
if (depth < mdepth) {
|
||||
// Create recursive split functions if maximum depth not reached
|
||||
std::thread left_thread([&]() { split(left, depth + 1, mdepth); });
|
||||
std::thread right_thread([&]() { split(right, depth + 1, mdepth); });
|
||||
|
||||
// Both threads must join before we could further work on the data viewed
|
||||
// by left and right (recursively sorted by the both calls)
|
||||
left_thread.join();
|
||||
right_thread.join();
|
||||
} else {
|
||||
// Do normal recursion in a single thread if maximum depth is reached
|
||||
split(left, depth + 1, mdepth);
|
||||
split(right, depth + 1, mdepth);
|
||||
}
|
||||
|
||||
// Merge left and right together before returning
|
||||
merge(data, left, right);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// Templated comparator function
|
||||
std::function<bool(T, T)> cmp;
|
||||
// Maximum depth
|
||||
const int max_depth;
|
||||
};
|
@ -32,6 +32,7 @@ auto main(int argc, char *argv[]) -> int {
|
||||
parser.addOption(sequential);
|
||||
parser.addOption(parallel);
|
||||
parser.addOption(nthreads);
|
||||
parser.addOption(output);
|
||||
|
||||
parser.addPositionalArgument("dataset", "Filename where to load the data from");
|
||||
parser.process(app);
|
||||
|
Loading…
Reference in New Issue
Block a user