forked from OctaForge/libostd
use introsort for sorting
This commit is contained in:
parent
f9a298c1b8
commit
c36a653824
|
@ -6,6 +6,8 @@
|
||||||
#ifndef OCTA_ALGORITHM_H
|
#ifndef OCTA_ALGORITHM_H
|
||||||
#define OCTA_ALGORITHM_H
|
#define OCTA_ALGORITHM_H
|
||||||
|
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
#include "octa/functional.h"
|
#include "octa/functional.h"
|
||||||
#include "octa/range.h"
|
#include "octa/range.h"
|
||||||
|
|
||||||
|
@ -43,30 +45,73 @@ namespace octa {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
struct UnaryCompare {
|
struct UnaryCompare {
|
||||||
T val;
|
const T &val;
|
||||||
U comp;
|
U comp;
|
||||||
bool operator()(const T &v) const { return comp(v, val); }
|
bool operator()(const T &v) const { return comp(v, val); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R, typename C>
|
template<typename R, typename C>
|
||||||
void quicksort(R range, C compare) {
|
void hs_sift_down(R range, size_t s, size_t e, C compare) {
|
||||||
|
size_t r = s;
|
||||||
|
while ((r * 2 + 1) <= e) {
|
||||||
|
size_t ch = r * 2 + 1;
|
||||||
|
size_t sw = r;
|
||||||
|
if (compare(range[sw], range[ch]))
|
||||||
|
sw = ch;
|
||||||
|
if (((ch + 1) <= e) && compare(range[sw], range[ch + 1]))
|
||||||
|
sw = ch + 1;
|
||||||
|
if (sw != r) {
|
||||||
|
swap(range[r], range[sw]);
|
||||||
|
r = sw;
|
||||||
|
} else return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R, typename C>
|
||||||
|
void heapsort(R range, C compare) {
|
||||||
|
size_t len = range.length();
|
||||||
|
size_t st = (len - 2) / 2;
|
||||||
|
for (;;) {
|
||||||
|
hs_sift_down(range, st, len - 1, compare);
|
||||||
|
if (st-- == 0) break;
|
||||||
|
}
|
||||||
|
size_t e = len - 1;
|
||||||
|
while (e > 0) {
|
||||||
|
swap(range[e], range[0]);
|
||||||
|
--e;
|
||||||
|
hs_sift_down(range, 0, e, compare);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R, typename C>
|
||||||
|
void introloop(R range, C compare, size_t depth) {
|
||||||
if (range.length() <= 10) {
|
if (range.length() <= 10) {
|
||||||
insertion_sort(range, compare);
|
insertion_sort(range, compare);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (depth == 0) {
|
||||||
|
heapsort(range, compare);
|
||||||
|
return;
|
||||||
|
}
|
||||||
typename RangeTraits<R>::reference p = range[range.length() / 2];
|
typename RangeTraits<R>::reference p = range[range.length() / 2];
|
||||||
swap(p, range.last());
|
swap(p, range.last());
|
||||||
R r = partition(range, UnaryCompare<decltype(p), C>{ p, compare });
|
R r = partition(range, UnaryCompare<decltype(p), C>{ p, compare });
|
||||||
R l = range.slice(0, range.length() - r.length());
|
R l = range.slice(0, range.length() - r.length());
|
||||||
swap(r.first(), r.last());
|
swap(r.first(), r.last());
|
||||||
quicksort(l, compare);
|
introloop(l, compare, depth - 1);
|
||||||
quicksort(r, compare);
|
introloop(r, compare, depth - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R, typename C>
|
||||||
|
void introsort(R range, C compare) {
|
||||||
|
introloop(range, compare, size_t(2
|
||||||
|
* (log(range.length()) / log(2))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename C>
|
template<typename R, typename C>
|
||||||
void sort(R range, C compare) {
|
void sort(R range, C compare) {
|
||||||
internal::quicksort(range, compare);
|
internal::introsort(range, compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
|
|
Loading…
Reference in a new issue