From c36a653824225da68e9b9c3ea519b594961d8ee9 Mon Sep 17 00:00:00 2001 From: q66 Date: Sat, 18 Apr 2015 23:12:45 +0100 Subject: [PATCH] use introsort for sorting --- octa/algorithm.h | 55 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/octa/algorithm.h b/octa/algorithm.h index e6abd32..81d9479 100644 --- a/octa/algorithm.h +++ b/octa/algorithm.h @@ -6,6 +6,8 @@ #ifndef OCTA_ALGORITHM_H #define OCTA_ALGORITHM_H +#include "math.h" + #include "octa/functional.h" #include "octa/range.h" @@ -43,30 +45,73 @@ namespace octa { namespace internal { template struct UnaryCompare { - T val; + const T &val; U comp; bool operator()(const T &v) const { return comp(v, val); } }; template - 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 + 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 + void introloop(R range, C compare, size_t depth) { if (range.length() <= 10) { insertion_sort(range, compare); return; } + if (depth == 0) { + heapsort(range, compare); + return; + } typename RangeTraits::reference p = range[range.length() / 2]; swap(p, range.last()); R r = partition(range, UnaryCompare{ p, compare }); R l = range.slice(0, range.length() - r.length()); swap(r.first(), r.last()); - quicksort(l, compare); - quicksort(r, compare); + introloop(l, compare, depth - 1); + introloop(r, compare, depth - 1); + } + + template + void introsort(R range, C compare) { + introloop(range, compare, size_t(2 + * (log(range.length()) / log(2)))); } } template void sort(R range, C compare) { - internal::quicksort(range, compare); + internal::introsort(range, compare); } template