<tb@panthema.net>
<http://www.gnu.org/licenses/>
#include "SortAlgo.h"
#include <algorithm>
#include <numeric>
#include <limits>
#include <inttypes.h>
typedef ArrayItem value_type;
const unsigned int inversion_count_instrumented = 512;
const struct AlgoEntry g_algolist[] =
{
{ _("Selection Sort"), &SelectionSort, UINT_MAX,
wxEmptyString },
{ _("Insertion Sort"), &InsertionSort, UINT_MAX,
wxEmptyString },
{ _("Binary Insertion Sort"), &BinaryInsertionSort, UINT_MAX,
wxEmptyString },
{ _("Merge Sort"), &MergeSort, 512,
_("Merge sort which merges two sorted sequences into a shadow array,"
"and then copies it back to the shown array.") },
{ _("Quick Sort (LR ptrs)"), &QuickSortLR, UINT_MAX,
_("Quick sort variant with left and right pointers.") },
{ _("Quick Sort (LL ptrs)"), &QuickSortLL, UINT_MAX,
_("Quick sort variant from 3rd edition of CLRS: two pointers on left.") },
{ _("Quick Sort (ternary, LR ptrs)"), &QuickSortTernaryLR, UINT_MAX,
_("Ternary-split quick sort variant, adapted from multikey quicksort by "
"Bentley & Sedgewick: partitions \"=<?>=\" using two pairs of pointers "
"at left and right, then copied to middle.") },
{ _("Quick Sort (ternary, LL ptrs)"), &QuickSortTernaryLL, UINT_MAX,
_("Ternary-split quick sort variant: partitions \"<>?=\" using two "
"pointers at left and one at right. Afterwards copies the \"=\" to middle.") },
{ _("Quick Sort (dual pivot)"), &QuickSortDualPivot, UINT_MAX,
_("Dual pivot quick sort variant: partitions \"<1<2?>\" using three pointers, "
"two at left and one at right.") },
{ _("Bubble Sort"), &BubbleSort, UINT_MAX,
wxEmptyString },
{ _("Cocktail Shaker Sort"), &CocktailShakerSort, UINT_MAX,
wxEmptyString },
{ _("Gnome Sort"), &GnomeSort, UINT_MAX,
wxEmptyString },
{ _("Comb Sort"), &CombSort, UINT_MAX,
wxEmptyString },
{ _("Shell Sort"), &ShellSort, 1024,
wxEmptyString },
{ _("Heap Sort"), &HeapSort, UINT_MAX,
wxEmptyString },
{ _("Smooth Sort"), &SmoothSort, 1024,
wxEmptyString },
{ _("Odd-Even Sort"), &OddEvenSort, 1024,
wxEmptyString },
{ _("Bitonic Sort"), &BitonicSort, UINT_MAX,
wxEmptyString },
{ _("Cycle Sort"), &CycleSort, UINT_MAX,
wxEmptyString },
{ _("Radix Sort (LSD)"), &RadixSortLSD, 512,
_("Least significant digit radix sort, which copies item into a shadow "
"array during counting.") },
{ _("Radix Sort (MSD)"), &RadixSortMSD, UINT_MAX,
_("Most significant digit radix sort, which permutes items in-place by walking cycles.") },
{ _("std::sort (gcc)"), &StlSort, inversion_count_instrumented,
wxEmptyString },
{ _("std::stable_sort (gcc)"), &StlStableSort, inversion_count_instrumented,
wxEmptyString },
{ _("std::sort_heap (gcc)"), &StlHeapSort, inversion_count_instrumented,
wxEmptyString },
{ _("Tim Sort"), &TimSort, inversion_count_instrumented,
wxEmptyString },
{ _("Block Merge Sort (WikiSort)"), &WikiSort, inversion_count_instrumented,
_("An O(1) place O(n log n) time stable merge sort.") },
{ _("Bogo Sort"), &BogoSort, UINT_MAX,
wxEmptyString },
{ _("Bozo Sort"), &BozoSort, UINT_MAX,
wxEmptyString },
{ _("Stooge Sort"), &StoogeSort, inversion_count_instrumented,
wxEmptyString },
{ _("Slow Sort"), &SlowSort, inversion_count_instrumented,
wxEmptyString }
};
const size_t g_algolist_size = sizeof(g_algolist) / sizeof(g_algolist[0]);
const struct AlgoEntry* g_algolist_end = g_algolist + g_algolist_size;
void SelectionSort(WSortView& A)
{
volatile ssize_t jMin = 0;
A.watch(&jMin, 3);
for (size_t i = 0; i < A.size()-1; ++i)
{
jMin = i;
for (size_t j = i+1; j < A.size(); ++j)
{
if (A[j] < A[jMin]) {
A.mark_swap(j, jMin);
jMin = j;
}
}
A.swap(i, jMin);
if (i > 0) A.unmark(i-1);
A.mark(i);
}
A.unwatch_all();
}
void InsertionSort(WSortView& A)
{
for (size_t i = 1; i < A.size(); ++i)
{
value_type key = A[i];
A.mark(i);
ssize_t j = i - 1;
while (j >= 0 && A[j] > key)
{
A.swap(j, j+1);
j--;
}
A.unmark(i);
}
}
void InsertionSort2(WSortView& A)
{
for (size_t i = 1; i < A.size(); ++i)
{
value_type tmp, key = A[i];
A.mark(i);
ssize_t j = i - 1;
while (j >= 0 && (tmp = A[j]) > key)
{
A.set(j + 1, tmp);
j--;
}
A.set(j + 1, key);
A.unmark(i);
}
}
void BinaryInsertionSort(WSortView& A)
{
for (size_t i = 1; i < A.size(); ++i)
{
value_type key = A[i];
A.mark(i);
int lo = 0, hi = i;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (key <= A[mid])
hi = mid;
else
lo = mid + 1;
}
ssize_t j = i - 1;
while (j >= lo)
{
A.swap(j, j+1);
j--;
}
A.unmark(i);
}
}
void Merge(WSortView& A, size_t lo, size_t mid, size_t hi)
{
A.mark(lo);
A.mark(mid,3);
A.mark(hi-1);
std::vector<value_type> out(hi-lo);
size_t i = lo, j = mid, o = 0;
while (i < mid && j < hi)
{
value_type ai = A[i], aj = A[j];
out[o++] = (ai < aj ? (++i, ai) : (++j, aj));
}
while (i < mid) out[o++] = A[i++];
while (j < hi) out[o++] = A[j++];
ASSERT(o == hi-lo);
A.unmark(mid);
for (i = 0; i < hi-lo; ++i)
A.set(lo + i, out[i]);
A.unmark(lo);
A.unmark(hi-1);
}
void MergeSort(WSortView& A, size_t lo, size_t hi)
{
if (lo + 1 < hi)
{
size_t mid = (lo + hi) / 2;
MergeSort(A, lo, mid);
MergeSort(A, mid, hi);
Merge(A, lo, mid, hi);
}
}
void MergeSort(WSortView& A)
{
return MergeSort(A, 0, A.size());
}
QuickSortPivotType g_quicksort_pivot = PIVOT_FIRST;
ssize_t QuickSortSelectPivot(WSortView& A, ssize_t lo, ssize_t hi)
{
if (g_quicksort_pivot == PIVOT_FIRST)
return lo;
if (g_quicksort_pivot == PIVOT_LAST)
return hi-1;
if (g_quicksort_pivot == PIVOT_MID)
return (lo + hi) / 2;
if (g_quicksort_pivot == PIVOT_RANDOM)
return lo + (rand() % (hi - lo));
if (g_quicksort_pivot == PIVOT_MEDIAN3)
{
ssize_t mid = (lo + hi) / 2;
if (A[lo] == A[mid]) return lo;
if (A[lo] == A[hi-1] || A[mid] == A[hi-1]) return hi-1;
return A[lo] < A[mid]
? (A[mid] < A[hi-1] ? mid : (A[lo] < A[hi-1] ? hi-1 : lo))
: (A[mid] > A[hi-1] ? mid : (A[lo] < A[hi-1] ? lo : hi-1));
}
return lo;
}
wxArrayString QuickSortPivotText()
{
wxArrayString sl;
sl.Add( _("First Item") );
sl.Add( _("Last Item") );
sl.Add( _("Middle Item") );
sl.Add( _("Random Item") );
sl.Add( _("Median of Three") );
return sl;
}
void QuickSortLR(WSortView& A, ssize_t lo, ssize_t hi)
{
volatile ssize_t p = QuickSortSelectPivot(A, lo, hi+1);
value_type pivot = A[p];
A.watch(&p, 2);
volatile ssize_t i = lo, j = hi;
A.watch(&i, 3);
A.watch(&j, 3);
while (i <= j)
{
while (A[i] < pivot)
i++;
while (A[j] > pivot)
j--;
if (i <= j)
{
A.swap(i,j);
if (p == i) p = j;
else if (p == j) p = i;
i++, j--;
}
}
A.unwatch_all();
if (lo < j)
QuickSortLR(A, lo, j);
if (i < hi)
QuickSortLR(A, i, hi);
}
void QuickSortLR(WSortView& A)
{
return QuickSortLR(A, 0, A.size()-1);
}
size_t PartitionLL(WSortView& A, size_t lo, size_t hi)
{
size_t p = QuickSortSelectPivot(A, lo, hi);
value_type pivot = A[p];
A.swap(p, hi-1);
A.mark(hi-1);
volatile ssize_t i = lo;
A.watch(&i, 3);
for (size_t j = lo; j < hi-1; ++j)
{
if (A[j] <= pivot) {
A.swap(i, j);
++i;
}
}
A.swap(i, hi-1);
A.unmark(hi-1);
A.unwatch_all();
return i;
}
void QuickSortLL(WSortView& A, size_t lo, size_t hi)
{
if (lo + 1 < hi)
{
size_t mid = PartitionLL(A, lo, hi);
QuickSortLL(A, lo, mid);
QuickSortLL(A, mid+1, hi);
}
}
void QuickSortLL(WSortView& A)
{
return QuickSortLL(A, 0, A.size());
}
void QuickSortTernaryLR(WSortView& A, ssize_t lo, ssize_t hi)
{
if (hi <= lo) return;
int cmp;
ssize_t piv = QuickSortSelectPivot(A, lo, hi+1);
A.swap(piv, hi);
A.mark(hi);
const value_type& pivot = A[hi];
volatile ssize_t i = lo, j = hi-1;
volatile ssize_t p = lo, q = hi-1;
A.watch(&i, 3);
A.watch(&j, 3);
for (;;)
{
while (i <= j && (cmp = A[i].cmp(pivot)) <= 0)
{
if (cmp == 0) {
A.mark(p,4);
A.swap(i, p++);
}
++i;
}
while (i <= j && (cmp = A[j].cmp(pivot)) >= 0)
{
if (cmp == 0) {
A.mark(q,4);
A.swap(j, q--);
}
--j;
}
if (i > j) break;
A.swap(i++, j--);
}
A.swap(i,hi);
A.mark_swap(i,hi);
ssize_t num_less = i - p;
ssize_t num_greater = q - j;
j = i-1; i = i+1;
ssize_t pe = lo + std::min(p-lo, num_less);
for (ssize_t k = lo; k < pe; k++, j--) {
A.swap(k,j);
A.mark_swap(k,j);
}
ssize_t qe = hi-1 - std::min(hi-1-q, num_greater-1);
for (ssize_t k = hi-1; k > qe; k--, i++) {
A.swap(i,k);
A.mark_swap(i,k);
}
A.unwatch_all();
A.unmark_all();
QuickSortTernaryLR(A, lo, lo + num_less - 1);
QuickSortTernaryLR(A, hi - num_greater + 1, hi);
}
void QuickSortTernaryLR(WSortView& A)
{
return QuickSortTernaryLR(A, 0, A.size()-1);
}
std::pair<ssize_t,ssize_t> PartitionTernaryLL(WSortView& A, ssize_t lo, ssize_t hi)
{
ssize_t p = QuickSortSelectPivot(A, lo, hi);
value_type pivot = A[p];
A.swap(p, hi-1);
A.mark(hi-1);
volatile ssize_t i = lo, k = hi-1;
A.watch(&i, 3);
for (ssize_t j = lo; j < k; ++j)
{
int cmp = A[j].cmp(pivot);
if (cmp == 0) {
A.swap(--k, j);
--j;
A.mark(k,4);
}
else if (cmp < 0) {
A.swap(i++, j);
}
}
A.unwatch_all();
ssize_t j = i + (hi-k);
for (ssize_t s = 0; s < hi-k; ++s) {
A.swap(i+s, hi-1-s);
A.mark_swap(i+s, hi-1-s);
}
A.unmark_all();
return std::make_pair(i,j);
}
void QuickSortTernaryLL(WSortView& A, size_t lo, size_t hi)
{
if (lo + 1 < hi)
{
std::pair<ssize_t,ssize_t> mid = PartitionTernaryLL(A, lo, hi);
QuickSortTernaryLL(A, lo, mid.first);
QuickSortTernaryLL(A, mid.second, hi);
}
}
void QuickSortTernaryLL(WSortView& A)
{
return QuickSortTernaryLL(A, 0, A.size());
}
void dualPivotYaroslavskiy(class WSortView& a, int left, int right)
{
if (right > left)
{
if (a[left] > a[right]) {
a.swap(left, right);
}
const value_type p = a[left];
const value_type q = a[right];
a.mark(left);
a.mark(right);
volatile ssize_t l = left + 1;
volatile ssize_t g = right - 1;
volatile ssize_t k = l;
a.watch(&l, 3);
a.watch(&g, 3);
a.watch(&k, 3);
while (k <= g)
{
if (a[k] < p) {
a.swap(k, l);
++l;
}
else if (a[k] >= q) {
while (a[g] > q && k < g) --g;
a.swap(k, g);
--g;
if (a[k] < p) {
a.swap(k, l);
++l;
}
}
++k;
}
--l;
++g;
a.swap(left, l);
a.swap(right, g);
a.unmark_all();
a.unwatch_all();
dualPivotYaroslavskiy(a, left, l - 1);
dualPivotYaroslavskiy(a, l + 1, g - 1);
dualPivotYaroslavskiy(a, g + 1, right);
}
}
void QuickSortDualPivot(class WSortView& a)
{
return dualPivotYaroslavskiy(a, 0, a.size()-1);
}
void BubbleSort(WSortView& A)
{
for (size_t i = 0; i < A.size()-1; ++i)
{
for (size_t j = 0; j < A.size()-1 - i; ++j)
{
if (A[j] > A[j + 1])
{
A.swap(j, j+1);
}
}
}
}
void CocktailShakerSort(WSortView& A)
{
size_t lo = 0, hi = A.size()-1, mov = lo;
while (lo < hi)
{
for (size_t i = hi; i > lo; --i)
{
if (A[i-1] > A[i])
{
A.swap(i-1, i);
mov = i;
}
}
lo = mov;
for (size_t i = lo; i < hi; ++i)
{
if (A[i] > A[i+1])
{
A.swap(i, i+1);
mov = i;
}
}
hi = mov;
}
}
void GnomeSort(WSortView& A)
{
for (size_t i = 1; i < A.size(); )
{
if (A[i] >= A[i-1])
{
++i;
}
else
{
A.swap(i, i-1);
if (i > 1) --i;
}
}
}
void CombSort(WSortView& A)
{
const double shrink = 1.3;
bool swapped = false;
size_t gap = A.size();
while ((gap > 1) || swapped)
{
if (gap > 1) {
gap = (size_t)((float)gap / shrink);
}
swapped = false;
for (size_t i = 0; gap + i < A.size(); ++i)
{
if (A[i] > A[i + gap])
{
A.swap(i, i+gap);
swapped = true;
}
}
}
}
void OddEvenSort(WSortView& A)
{
bool sorted = false;
while (!sorted)
{
sorted = true;
for (size_t i = 1; i < A.size()-1; i += 2)
{
if(A[i] > A[i+1])
{
A.swap(i, i+1);
sorted = false;
}
}
for (size_t i = 0; i < A.size()-1; i += 2)
{
if(A[i] > A[i+1])
{
A.swap(i, i+1);
sorted = false;
}
}
}
}
void ShellSort(WSortView& A)
{
size_t incs[16] = { 1391376, 463792, 198768, 86961, 33936,
13776, 4592, 1968, 861, 336,
112, 48, 21, 7, 3, 1 };
for (size_t k = 0; k < 16; k++)
{
for (size_t h = incs[k], i = h; i < A.size(); i++)
{
value_type v = A[i];
size_t j = i;
while (j >= h && A[j-h] > v)
{
A.set(j, A[j-h]);
j -= h;
}
A.set(j, v);
}
}
}
bool isPowerOfTwo(size_t x)
{
return ((x != 0) && !(x & (x - 1)));
}
uint32_t prevPowerOfTwo(uint32_t x)
{
x |= x >> 1; x |= x >> 2; x |= x >> 4;
x |= x >> 8; x |= x >> 16;
return x - (x >> 1);
}
void HeapSort(WSortView& A)
{
size_t n = A.size(), i = n / 2;
for (size_t j = i; j < n; ++j)
A.mark(j, log(prevPowerOfTwo(j+1)) / log(2) + 4);
while (1)
{
if (i > 0) {
i--;
}
else {
n--;
if (n == 0) return;
A.swap(0,n);
A.mark(n);
if (n+1 < A.size()) A.unmark(n+1);
}
size_t parent = i;
size_t child = i*2 + 1;
while (child < n)
{
if (child + 1 < n && A[child + 1] > A[child]) {
child++;
}
if (A[child] > A[parent]) {
A.swap(parent, child);
parent = child;
child = parent*2+1;
}
else {
break;
}
}
A.mark(i, log(prevPowerOfTwo(i+1)) / log(2) + 4);
}
}
void RadixSortMSD(WSortView& A, size_t lo, size_t hi, size_t depth)
{
A.mark(lo); A.mark(hi-1);
const unsigned int RADIX = 4;
unsigned int pmax = floor( log(A.array_max()+1) / log(RADIX) );
ASSERT(depth <= pmax);
size_t base = pow(RADIX, pmax - depth);
std::vector<size_t> count(RADIX, 0);
for (size_t i = lo; i < hi; ++i)
{
size_t r = A[i].get() / base % RADIX;
ASSERT(r < RADIX);
count[r]++;
}
std::vector<size_t> bkt(RADIX, 0);
std::partial_sum(count.begin(), count.end(), bkt.begin());
for (size_t i = 0; i < bkt.size(); ++i) {
if (bkt[i] == 0) continue;
A.mark(lo + bkt[i]-1, 3);
}
for (size_t i=0, j; i < (hi-lo); )
{
while ( (j = --bkt[ (A[lo+i].get() / base % RADIX) ]) > i )
{
A.swap(lo + i, lo + j);
}
i += count[ (A[lo+i].get() / base % RADIX) ];
}
A.unmark_all();
if (depth+1 > pmax) return;
size_t sum = lo;
for (size_t i = 0; i < RADIX; ++i)
{
if (count[i] <= 1) continue;
RadixSortMSD(A, sum, sum+count[i], depth+1);
sum += count[i];
}
}
void RadixSortMSD(WSortView& A)
{
return RadixSortMSD(A, 0, A.size(), 0);
}
void RadixSortLSD(WSortView& A)
{
const unsigned int RADIX = 4;
unsigned int pmax = ceil( log(A.array_max()+1) / log(RADIX) );
for (unsigned int p = 0; p < pmax; ++p)
{
size_t base = pow(RADIX, p);
std::vector<size_t> count(RADIX, 0);
std::vector<value_type> copy(A.size());
for (size_t i = 0; i < A.size(); ++i)
{
size_t r = (copy[i] = A[i]).get() / base % RADIX;
ASSERT(r < RADIX);
count[r]++;
}
std::vector<size_t> bkt(RADIX+1, 0);
std::partial_sum(count.begin(), count.end(), bkt.begin()+1);
for (size_t i = 0; i < bkt.size()-1; ++i) {
if (bkt[i] >= A.size()) continue;
A.mark(bkt[i], 3);
}
for (size_t i=0; i < A.size(); ++i)
{
size_t r = copy[i].get() / base % RADIX;
A.set( bkt[r]++, copy[i] );
}
A.unmark_all();
}
}
void StlSort(WSortView& A)
{
std::sort(MyIterator(&A,0), MyIterator(&A,A.size()));
}
void StlStableSort(WSortView& A)
{
std::stable_sort(MyIterator(&A,0), MyIterator(&A,A.size()));
}
void StlHeapSort(WSortView& A)
{
std::make_heap(MyIterator(&A,0), MyIterator(&A,A.size()));
std::sort_heap(MyIterator(&A,0), MyIterator(&A,A.size()));
}
bool BogoCheckSorted(WSortView& A)
{
size_t i;
value_type prev = A[0];
A.mark(0);
for (i = 1; i < A.size(); ++i)
{
value_type val = A[i];
if (prev > val) break;
prev = val;
A.mark(i);
}
if (i == A.size()) {
return true;
}
while (i > 0) A.unmark(i--);
A.unmark(0);
return false;
}
void BogoSort(WSortView& A)
{
std::vector<size_t> perm(A.size());
for (size_t i = 0; i < A.size(); ++i)
perm[i] = i;
while (1)
{
if (BogoCheckSorted(A)) break;
std::random_shuffle(perm.begin(), perm.end());
std::vector<char> pmark(A.size(), 0);
for (size_t i = 0; i < A.size(); ++i)
{
if (pmark[i]) continue;
size_t j = i;
while ( perm[j] != i )
{
ASSERT(!pmark[j]);
A.swap(j, perm[j]);
pmark[j] = 1;
j = perm[j];
}
ASSERT(!pmark[j]);
pmark[j] = 1;
}
for (size_t i = 0; i < A.size(); ++i)
ASSERT(pmark[i]);
}
}
void BozoSort(WSortView& A)
{
srand(time(NULL));
while (1)
{
if (BogoCheckSorted(A)) break;
A.swap(rand() % A.size(), rand() % A.size());
}
}
namespace BitonicSortNS {
static const bool ASCENDING = true;
static void compare(WSortView& A, int i, int j, bool dir)
{
if (dir == (A[i] > A[j]))
A.swap(i, j);
}
static int greatestPowerOfTwoLessThan(int n)
{
int k = 1;
while (k < n) k = k << 1;
return k >> 1;
}
static void bitonicMerge(WSortView& A, int lo, int n, bool dir)
{
if (n > 1)
{
int m = greatestPowerOfTwoLessThan(n);
for (int i = lo; i < lo + n - m; i++)
compare(A, i, i+m, dir);
bitonicMerge(A, lo, m, dir);
bitonicMerge(A, lo + m, n - m, dir);
}
}
static void bitonicSort(WSortView& A, int lo, int n, bool dir)
{
if (n > 1)
{
int m = n / 2;
bitonicSort(A, lo, m, !dir);
bitonicSort(A, lo + m, n - m, dir);
bitonicMerge(A, lo, n, dir);
}
}
}
void BitonicSort(WSortView& A)
{
BitonicSortNS::bitonicSort(A, 0, A.size(), BitonicSortNS::ASCENDING);
}
namespace SmoothSortNS {
static const int LP[] = {
1, 1, 3, 5, 9, 15, 25, 41, 67, 109,
177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891,
35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457,
1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703,
48315633, 78176337, 126491971, 204668309, 331160281, 535828591,
866988873
};
static void sift(WSortView& A, int pshift, int head)
{
value_type val = A[head];
while (pshift > 1)
{
int rt = head - 1;
int lf = head - 1 - LP[pshift - 2];
if (val.cmp(A[lf]) >= 0 && val.cmp(A[rt]) >= 0)
break;
if (A[lf].cmp(A[rt]) >= 0) {
A.set(head, A[lf]);
head = lf;
pshift -= 1;
}
else {
A.set(head, A[rt]);
head = rt;
pshift -= 2;
}
}
A.set(head, val);
}
static void trinkle(WSortView& A, int p, int pshift, int head, bool isTrusty)
{
value_type val = A[head];
while (p != 1)
{
int stepson = head - LP[pshift];
if (A[stepson].cmp(val) <= 0)
break;
if (!isTrusty && pshift > 1) {
int rt = head - 1;
int lf = head - 1 - LP[pshift - 2];
if (A[rt].cmp(A[stepson]) >= 0 ||
A[lf].cmp(A[stepson]) >= 0)
break;
}
A.set(head, A[stepson]);
head = stepson;
int trail = __builtin_ctz(p & ~1);
p >>= trail;
pshift += trail;
isTrusty = false;
}
if (!isTrusty) {
A.set(head, val);
sift(A, pshift, head);
}
}
void sort(WSortView& A, int lo, int hi)
{
int head = lo;
int p = 1;
int pshift = 1;
while (head < hi)
{
if ((p & 3) == 3) {
sift(A, pshift, head);
p >>= 2;
pshift += 2;
}
else {
if (LP[pshift - 1] >= hi - head) {
trinkle(A, p, pshift, head, false);
} else {
sift(A, pshift, head);
}
if (pshift == 1) {
p <<= 1;
pshift--;
} else {
p <<= (pshift - 1);
pshift = 1;
}
}
p |= 1;
head++;
}
trinkle(A, p, pshift, head, false);
while (pshift != 1 || p != 1)
{
if (pshift <= 1) {
int trail = __builtin_ctz(p & ~1);
p >>= trail;
pshift += trail;
}
else {
p <<= 2;
p ^= 7;
pshift -= 2;
trinkle(A, p >> 1, pshift + 1, head - LP[pshift] - 1, true);
trinkle(A, p, pshift, head - 1, true);
}
head--;
}
}
}
void SmoothSort(WSortView& A)
{
return SmoothSortNS::sort(A, 0, A.size()-1);
}
void StoogeSort(WSortView& A, int i, int j)
{
if (A[i] > A[j])
{
A.swap(i, j);
}
if (j - i + 1 >= 3)
{
int t = (j - i + 1) / 3;
A.mark(i, 3);
A.mark(j, 3);
StoogeSort(A, i, j-t);
StoogeSort(A, i+t, j);
StoogeSort(A, i, j-t);
A.unmark(i);
A.unmark(j);
}
}
void StoogeSort(WSortView& A)
{
StoogeSort(A, 0, A.size()-1);
}
void SlowSort(WSortView& A, int i, int j)
{
if (i >= j) return;
int m = (i + j) / 2;
SlowSort(A, i, m);
SlowSort(A, m+1, j);
if (A[m] > A[j])
A.swap(m, j);
A.mark(j, 2);
SlowSort(A, i, j-1);
A.unmark(j);
}
void SlowSort(WSortView& A)
{
SlowSort(A, 0, A.size()-1);
}
void CycleSort(WSortView& array, ssize_t n)
{
volatile ssize_t cycleStart = 0;
array.watch(&cycleStart, 16);
volatile ssize_t rank = 0;
array.watch(&rank, 3);
for (cycleStart = 0; cycleStart < n - 1; ++cycleStart)
{
value_type& item = array.get_mutable(cycleStart);
do {
rank = cycleStart;
for (ssize_t i = cycleStart + 1; i < n; ++i)
{
if (array[i] < item)
rank++;
}
if (rank == cycleStart) {
array.mark(rank, 2);
break;
}
while (item == array[rank])
rank++;
std::swap(array.get_mutable(rank), item);
array.mark(rank, 2);
}
while (rank != cycleStart);
}
array.unwatch_all();
}
void CycleSort(WSortView& A)
{
CycleSort(A, A.size());
}