std::pair<ssize_t,ssize_t> PartitionTernaryLL(SortArray& A, ssize_t lo, ssize_t hi) { // pick pivot and swap to back 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); // ternary comparison if (cmp == 0) { A.swap(--k, j); --j; // reclassify A[j] A.mark(k,4); } else if (cmp < 0) { A.swap(i++, j); } } // unwatch i, because the pivot is swapped there // in the first step of the following swap loop. 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 QuickSortTernaryLR(SortArray& A, ssize_t lo, ssize_t hi) { if (hi <= lo) return; int cmp; // pick pivot and swap to back ssize_t piv = QuickSortSelectPivot(A, lo, hi+1); A.swap(piv, hi); A.mark(hi); const value_type& pivot = A[hi]; // schema: |p === |i <<< | ??? |j >>> |q === |piv 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 (;;) { // partition on left while (i <= j && (cmp = A[i].cmp(pivot)) <= 0) { if (cmp == 0) { A.mark(p,4); A.swap(i, p++); } ++i; } // partition on right 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; // swap item between < > regions A.swap(i++, j--); } // swap pivot to right place A.swap(i,hi); A.mark_swap(i,hi); ssize_t num_less = i - p; ssize_t num_greater = q - j; // swap equal ranges into center, but avoid swapping equal elements 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); // one already greater at end 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); }