|
1 | | -#ifndef ZOO_QUICKSORT |
2 | | -#define ZOO_QUICKSORT |
3 | | - |
4 | | -#include <zoo/algorithm/moveRotation.h> // for moveRotate |
5 | | - |
6 | | -#include <zoo/algorithm/less.h> |
7 | | - |
8 | | -#include <array> // for temporary storage |
9 | | -#include <stdexcept> |
10 | | - |
11 | | -namespace zoo { |
12 | | - |
13 | | -template<typename FI> |
14 | | -struct ImplicitPivotResult { |
15 | | - FI pivot_; |
16 | | - long bias_; |
17 | | -}; |
18 | | - |
19 | | -/// \tparam FI is a forward iterator |
20 | | -/// \pre b != e |
21 | | -template<typename FI, typename Comparison> |
22 | | -auto implicitPivotPartition(FI b, FI e, Comparison cmp) -> |
23 | | - ImplicitPivotResult<FI> |
24 | | -{ |
25 | | - auto bias = 0; |
26 | | - auto pivot = b++; |
27 | | - /*if(e == b) { return pivot; } |
28 | | - if(cmp(*b, *pivot)) { |
29 | | - auto third = next(b); |
30 | | - if(third == e) { |
31 | | - moveRotation(*pivot, *b); |
32 | | - return pivot; |
33 | | - } |
34 | | - }*/ |
35 | | - for(; b != e; ++b) { |
36 | | - // invariant: ..., L0, P == *pivot, G0, G1, ... Gn, *b |
37 | | - // where Lx means lower-than-pivot and Gx higher-equal-to-pivot |
38 | | - if(!cmp(*b, *pivot)) { |
39 | | - ++bias; |
40 | | - continue; |
41 | | - } |
42 | | - --bias; |
43 | | - // ..., L1, P == *pivot, G0, G1, ..., Gn, L0 == *b, X0, ... |
44 | | - // The pivot is greater than the element: |
45 | | - // insert *b into the lower partition: |
46 | | - // 1. *b goes into the pivot position |
47 | | - // 2. the pivot increases by one |
48 | | - // 3. the element at pivot + 1, the new pivot, must be greater |
49 | | - // than or equal to any Lx, the value of *pivot satisfies this |
50 | | - // property. |
51 | | - // These requirements can be satisfied by rotating the elements |
52 | | - // at positions (pivot, b, pivot + 1) |
53 | | - // ..., L1, L0, P == *pivot, G1, ..., Gn, G0 == *b, X0, ... |
54 | | - auto oldPivot = pivot++; |
55 | | - if(b == pivot) { |
56 | | - moveRotation(*oldPivot, *pivot); |
57 | | - } else { |
58 | | - moveRotation(*oldPivot, *b, *pivot); |
59 | | - } |
60 | | - // tmp = *b, *b = *1, *1 = *0, *0 = tmp |
61 | | - /*moveRotation(*oldPivot, *b); |
62 | | - moveRotation(*b, *pivot);*/ |
63 | | - } |
64 | | - return {pivot, bias}; |
65 | | -} |
66 | | - |
67 | | -template<typename I, typename Comparison = Less> |
68 | | -void quicksort(I begin, I end, Comparison cmp = Comparison{}) { |
69 | | - if(begin == end) { return; } |
70 | | - |
71 | | - constexpr static const auto FrameCount = 64; |
72 | | - struct Frame { |
73 | | - I b, e; |
74 | | - }; |
75 | | - std::array<Frame, FrameCount> stack; |
76 | | - auto index = 0; |
77 | | - |
78 | | - for(;;) { |
79 | | - auto result = implicitPivotPartition(begin, end, cmp); |
80 | | - auto pivot = result.pivot_; |
81 | | - auto bias = result.bias_; |
82 | | - auto higherBegin = next(pivot); |
83 | | - if(higherBegin == end) { // no higher-recursion needed |
84 | | - if(begin != pivot) { |
85 | | - end = pivot; // then just do lower recursion |
86 | | - continue; // without leaving a frame |
87 | | - } |
88 | | - // there is no lower-recursion either |
89 | | - if(!index) { return; } |
90 | | - auto &frame = stack[--index]; |
91 | | - begin = frame.b; |
92 | | - end = frame.e; |
93 | | - continue; |
94 | | - } |
95 | | - // higher recursion needed |
96 | | - if(begin == pivot) { // no lower recursion needed |
97 | | - begin = higherBegin; // becomes the higher recursion |
98 | | - continue; |
99 | | - } |
100 | | - // both lower and higher recursions needed, make frame for the larger |
101 | | - // partition: |
102 | | - // The smaller partition is less than or equal to half the elements: |
103 | | - // size(smaller) <= size/2 => depth of recursion <= log2(N) |
104 | | - if(0 < bias) { // lower partition is smaller |
105 | | - stack[index] = { higherBegin, end }; |
106 | | - end = pivot; |
107 | | - } else { // higher partition is smaller |
108 | | - stack[index] = { begin, pivot }; |
109 | | - begin = higherBegin; |
110 | | - } |
111 | | - if(FrameCount <= ++index) { |
112 | | - throw std::runtime_error("quicksort stack exhausted"); |
113 | | - } |
114 | | - } |
115 | | -} |
116 | | - |
117 | | -template<typename FI, typename Comparison = Less> |
118 | | -bool is_sorted(FI begin, FI end, Comparison cmp = Comparison{}) { |
119 | | - if(begin == end) { return true; } |
120 | | - auto old = begin++; |
121 | | - while(begin != end) { |
122 | | - if(not cmp(*old, *begin)) { return false; } |
123 | | - old = begin++; |
124 | | - } |
125 | | - return true; |
126 | | -} |
127 | | - |
128 | | -} |
129 | | - |
130 | | -#endif |
| 1 | +#ifndef ZOO_QUICKSORT |
| 2 | +#define ZOO_QUICKSORT |
| 3 | + |
| 4 | +#include <zoo/algorithm/moveRotation.h> // for moveRotate |
| 5 | + |
| 6 | +#include <zoo/algorithm/less.h> |
| 7 | + |
| 8 | +#include <array> // for temporary storage |
| 9 | +#include <stdexcept> |
| 10 | +#include <ciso646> |
| 11 | + |
| 12 | +namespace zoo { |
| 13 | + |
| 14 | +template<typename FI> |
| 15 | +struct ImplicitPivotResult { |
| 16 | + FI pivot_; |
| 17 | + long bias_; |
| 18 | +}; |
| 19 | + |
| 20 | +/// \tparam FI is a forward iterator |
| 21 | +/// \pre b != e |
| 22 | +template<typename FI, typename Comparison> |
| 23 | +auto implicitPivotPartition(FI b, FI e, Comparison cmp) -> |
| 24 | + ImplicitPivotResult<FI> |
| 25 | +{ |
| 26 | + auto bias = 0; |
| 27 | + auto pivot = b++; |
| 28 | + /*if(e == b) { return pivot; } |
| 29 | + if(cmp(*b, *pivot)) { |
| 30 | + auto third = next(b); |
| 31 | + if(third == e) { |
| 32 | + moveRotation(*pivot, *b); |
| 33 | + return pivot; |
| 34 | + } |
| 35 | + }*/ |
| 36 | + for(; b != e; ++b) { |
| 37 | + // invariant: ..., L0, P == *pivot, G0, G1, ... Gn, *b |
| 38 | + // where Lx means lower-than-pivot and Gx higher-equal-to-pivot |
| 39 | + if(!cmp(*b, *pivot)) { |
| 40 | + ++bias; |
| 41 | + continue; |
| 42 | + } |
| 43 | + --bias; |
| 44 | + // ..., L1, P == *pivot, G0, G1, ..., Gn, L0 == *b, X0, ... |
| 45 | + // The pivot is greater than the element: |
| 46 | + // insert *b into the lower partition: |
| 47 | + // 1. *b goes into the pivot position |
| 48 | + // 2. the pivot increases by one |
| 49 | + // 3. the element at pivot + 1, the new pivot, must be greater |
| 50 | + // than or equal to any Lx, the value of *pivot satisfies this |
| 51 | + // property. |
| 52 | + // These requirements can be satisfied by rotating the elements |
| 53 | + // at positions (pivot, b, pivot + 1) |
| 54 | + // ..., L1, L0, P == *pivot, G1, ..., Gn, G0 == *b, X0, ... |
| 55 | + auto oldPivot = pivot++; |
| 56 | + if(b == pivot) { |
| 57 | + moveRotation(*oldPivot, *pivot); |
| 58 | + } else { |
| 59 | + moveRotation(*oldPivot, *b, *pivot); |
| 60 | + } |
| 61 | + // tmp = *b, *b = *1, *1 = *0, *0 = tmp |
| 62 | + /*moveRotation(*oldPivot, *b); |
| 63 | + moveRotation(*b, *pivot);*/ |
| 64 | + } |
| 65 | + return {pivot, bias}; |
| 66 | +} |
| 67 | + |
| 68 | +template<typename I, typename Comparison = Less> |
| 69 | +void quicksort(I begin, I end, Comparison cmp = Comparison{}) { |
| 70 | + if(begin == end) { return; } |
| 71 | + |
| 72 | + constexpr static const auto FrameCount = 64; |
| 73 | + struct Frame { |
| 74 | + I b, e; |
| 75 | + }; |
| 76 | + std::array<Frame, FrameCount> stack; |
| 77 | + auto index = 0; |
| 78 | + |
| 79 | + for(;;) { |
| 80 | + auto result = implicitPivotPartition(begin, end, cmp); |
| 81 | + auto pivot = result.pivot_; |
| 82 | + auto bias = result.bias_; |
| 83 | + auto higherBegin = next(pivot); |
| 84 | + if(higherBegin == end) { // no higher-recursion needed |
| 85 | + if(begin != pivot) { |
| 86 | + end = pivot; // then just do lower recursion |
| 87 | + continue; // without leaving a frame |
| 88 | + } |
| 89 | + // there is no lower-recursion either |
| 90 | + if(!index) { return; } |
| 91 | + auto &frame = stack[--index]; |
| 92 | + begin = frame.b; |
| 93 | + end = frame.e; |
| 94 | + continue; |
| 95 | + } |
| 96 | + // higher recursion needed |
| 97 | + if(begin == pivot) { // no lower recursion needed |
| 98 | + begin = higherBegin; // becomes the higher recursion |
| 99 | + continue; |
| 100 | + } |
| 101 | + // both lower and higher recursions needed, make frame for the larger |
| 102 | + // partition: |
| 103 | + // The smaller partition is less than or equal to half the elements: |
| 104 | + // size(smaller) <= size/2 => depth of recursion <= log2(N) |
| 105 | + if(0 < bias) { // lower partition is smaller |
| 106 | + stack[index] = { higherBegin, end }; |
| 107 | + end = pivot; |
| 108 | + } else { // higher partition is smaller |
| 109 | + stack[index] = { begin, pivot }; |
| 110 | + begin = higherBegin; |
| 111 | + } |
| 112 | + if(FrameCount <= ++index) { |
| 113 | + throw std::runtime_error("quicksort stack exhausted"); |
| 114 | + } |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +template<typename FI, typename Comparison = Less> |
| 119 | +bool is_sorted(FI begin, FI end, Comparison cmp = Comparison{}) { |
| 120 | + if(begin == end) { return true; } |
| 121 | + auto old = begin++; |
| 122 | + while(begin != end) { |
| 123 | + if(not cmp(*old, *begin)) { return false; } |
| 124 | + old = begin++; |
| 125 | + } |
| 126 | + return true; |
| 127 | +} |
| 128 | + |
| 129 | +} |
| 130 | + |
| 131 | +#endif |
0 commit comments