142 lines
4.0 KiB
C++
Raw Normal View History

2025-07-28 22:25:26 +02:00
#include "sorter.hpp"
#include <algorithm>
#include <iterator>
#include <cassert>
#include <iostream>
2025-07-30 15:05:52 +02:00
#include <bitset>
#include <climits>
2025-07-28 22:25:26 +02:00
#define DEBUG false
2025-07-28 22:25:26 +02:00
namespace ae {
void sorter::sort(container& data) {
for (auto i = 1uz; i < data.placeholder_.size(); ++i) {
std::ranges::copy(data.placeholder_[i], std::back_inserter(data.placeholder_[0]));
data.placeholder_[i].clear();
}
#if DEBUG
std::vector<container::element_type> copy;
std::ranges::copy(data.placeholder_[0], std::back_inserter(copy));
std::sort(copy.begin(), copy.end());
#endif
sorter::msd_inplace_radix_sort(data.placeholder_[0], 0, [&](auto span) {sorter::robin_hood_sort(span);});
#if DEBUG
for (int i = 0; i < copy.size(); i++) {
if (copy[i] != data.placeholder_[0][i])
std::cerr << i << " " << "sorted: " << copy[i] << " actual:" << data.placeholder_[0][i] << std::endl;
}
#endif
2025-07-28 22:25:26 +02:00
}
void sorter::msd_inplace_radix_sort(
std::span<container::element_type> range,
size_t passes,
const std::function<void(std::span<container::element_type> bucket)>& bucket_sort
) {
if (std::begin(range) >= std::end(range)) {
return;
}
if (sorter::RADIX_ITERATIONS == passes) {
switch (range.size()) {
case 1: return;
case 2:
if (range[0] >= range[1]) {
std::swap(range[0], range[1]);
}
return;
default:
bucket_sort(range);
return;
}
if (range.size() > 1) {
2025-07-30 15:05:52 +02:00
bucket_sort(range);
}
2025-07-28 22:25:26 +02:00
return;
}
auto lower = std::begin(range);
auto upper = std::end(range);
while (lower < upper) {
if (*lower & (1L << (sizeof(container::element_type) * CHAR_BIT - passes - 1))) {
// The <passes>-left bit is set, so move to the beginning of the end section and decrement the upper iterator
--upper;
std::swap(*upper, *lower);
} else {
++lower;
}
}
#if DEBUG
std::cerr << "pass: " << passes << " begin: " << &*std::begin(range) << " end: " << &*std::end(range) << " lower: " << &*lower << std::endl;
#endif
sorter::msd_inplace_radix_sort(std::span<container::element_type> (std::begin(range), lower), passes + 1, bucket_sort);
sorter::msd_inplace_radix_sort(std::span<container::element_type> (lower, std::end(range)), passes + 1, bucket_sort);
}
void sorter::robin_hood_sort(std::span<container::element_type> bucket) {
const auto size = bucket.size() + sorter::OVERHEAD_SIZE;
2025-07-30 15:05:52 +02:00
const auto mask = ((1L) << (sizeof(container::element_type) * CHAR_BIT - sorter::RADIX_ITERATIONS)) - 1;
std::vector<container::element_type> space(size, -1L);
for (auto element : bucket) {
auto masked_element = (element & mask);
auto index = ((masked_element) * bucket.size()) / mask;
if (space[index] == -1) {
space[index] = element;
2025-07-28 22:25:26 +02:00
} else {
#if DEBUG
std::cerr << "Linear probing of " << element << " at index " << index << ". Current element " << space[index] << std::endl;
#endif
auto i = index;
// linear probing
while (i < size - 1 && space[i] != -1) {++i;};
#if DEBUG
std::cerr << "Inserting " << element << " at index " << i << " instead of " << index << std::endl;
#endif
space[i] = element;
}
}
#if DEBUG
std::cerr << "Unsorted\n";
for (auto element : space) {
std::cerr << element << " ";
}
std::cerr << std::endl;
#endif
2025-07-28 22:25:26 +02:00
// One final pass to correct linear probing errors
for (auto i = 1; i < size; ++i) {
auto j = i;
while ((uint64_t) space[j-1] > space[j] && j > 0) {
std::swap((space[j]),space[j-1]);
j--;
2025-07-28 22:25:26 +02:00
}
}
#if DEBUG
std::cerr << "Original\n";
for (auto element : bucket) {
std::cerr << element << " ";
}
std::cerr << std::endl;
std::cerr << "Checking if sorted\n";
for (auto element : space) {
std::cerr << element << " ";
}
std::cerr << std::endl;
#endif
// copy data back into original range
auto i = 0;
for (auto element = std::begin(bucket); element < std::end(bucket); ++element) {
*element = space[i];
++i;
}
2025-07-28 22:25:26 +02:00
}
} // namespace ae