-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathQuickSelect.hpp
More file actions
198 lines (163 loc) · 5.75 KB
/
QuickSelect.hpp
File metadata and controls
198 lines (163 loc) · 5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#ifndef ALGORITHMS_QUICKSELECT_HPP
#define ALGORITHMS_QUICKSELECT_HPP
#include <span> // std::span
#include <array> // std::array
#include <vector> // std::vector
#include "Comparable.hpp" // includes Comparable concept used as a constraint
#include <cassert> // std::assert
#include <stdexcept> // std::invalid_argument
/**
* The {@code QuickSelect} class provides a public method for selecting the ith smallest element
* in an array using quicksort.
*
* @author Benjamin Chan
*
* Adapted from Algorithms, 4th edition, {@authors Robert Sedgewick and Kevin Wayne}
* and their booksite https://algs4.cs.princeton.edu/
*
* The Java program from which this C++ code was adapted from is found at
* https://algs4.cs.princeton.edu/23quicksort/Quick.java.html.
*
* @param <T> the generic type of an item in this sorting algorithm
*/
template<typename T> requires Comparable<T>
class QuickSelect {
public:
explicit QuickSelect<T>(span<T> a, bool reverse = false) {
this->container = a;
}
/**
* Rearranges the container so that {@code a[k]} contains the kth smallest key;
* {@code a[0]} through {@code a[k-1]} are less than (or equal to) {@code a[k]}; and
* {@code a[k+1]} through {@code a[n-1]} are greater than (or equal to) {@code a[k]}.
*
* @param k the rank of the key
* @return the key of rank {@code k}
* @throws IllegalArgumentException unless {@code 0 <= k < a.length}
*/
int rankOf(int rank, bool reverse = false);
private:
span<T> container;
void sort(span<T> a, int lo, int hi, bool reverse = false);
int partition(span<T> a, int lo, int hi, bool reverse = false);
void exch(span<T> a, int i, int j);
// check if entire container is sorted -- useful for debugging
bool isSorted(span<T> a, int lo, int hi, bool reverse = false);
// check if container is sorted between two indices, lo and hi -- useful for debugging
bool isSorted(span<T> a, bool reverse = false);
};
template<typename T>
requires Comparable<T>
int QuickSelect<T>::rankOf(int rank, bool reverse) {
int containerLength = this->container.size();
if (rank < 0 || rank >= containerLength) {
throw invalid_argument("index is not between 0 and " + to_string(containerLength) + ": " +
to_string(rank));
}
random_device rd;
mt19937 g(rd());
shuffle(container.begin(), container.end(), g);
int lo = 0, hi = containerLength - 1;
while (hi > lo) {
int i = partition(container, lo, hi, reverse);
if (i > rank) hi = i - 1;
else if (i < rank) lo = i + 1;
else return container[i];
}
return container[lo];
}
template<typename T>
requires Comparable<T>
void QuickSelect<T>::sort(span<T> a, int lo, int hi, bool reverse) {
if (hi <= lo) return;
int j = partition(a, lo, hi, reverse);
sort(a, lo, j - 1, reverse);
sort(a, j + 1, hi, reverse);
assert(isSorted(a, lo, hi, reverse));
}
template<typename T>
requires Comparable<T>
int QuickSelect<T>::partition(span<T> a, int lo, int hi, bool reverse) {
int i = lo;
int j = hi + 1;
T v = a[lo];
if (!reverse) {
while (true) {
// find item on lo to swap
while (a[++i] < v) {
if (i == hi) break;
}
// find item on hi to swap
while (v < a[--j]) {
if (j == lo) break; // redundant since a[lo] acts as sentinel
}
// check if pointers cross
if (i >= j) break;
exch(a, i, j);
}
} else {
while (true) {
// find item on lo to swap
while (a[++i] > v) {
if (i == hi) break;
}
// find item on hi to swap
while (v > a[--j]) {
if (j == lo) break; // redundant since a[lo] acts as sentinel
}
// check if pointers cross
if (i >= j) break;
exch(a, i, j);
}
}
// put partitioning item v at a[j]
exch(a, lo, j);
// now, a[lo .. j-1] <= a[j] <= a[j+1 .. hi]
return j;
}
template<typename T>
requires Comparable<T>
void QuickSelect<T>::exch(span<T> a, int i, int j) {
T swap = a[i];
a[i] = a[j];
a[j] = swap;
}
template<typename T>
requires Comparable<T>
bool QuickSelect<T>::isSorted(span<T> a, bool reverse) {
return isSorted(a, 0, a.size() - 1, reverse);
}
template<typename T>
requires Comparable<T>
bool QuickSelect<T>::isSorted(span<T> a, int lo, int hi, bool reverse) {
if (!reverse) {
for (int i = lo + 1; i <= hi; i++)
if (a[i] < a[i - 1]) return false;
return true;
} else {
for (int i = lo + 1; i <= hi; i++)
if (a[i] > a[i - 1]) return false;
return true;
}
}
/**
* Deduct the type, <T>, of the QuickSelect class based on constructor argument types
* and number of arguments
*/
template<typename T> requires Comparable<T>
QuickSelect(span<T>) -> QuickSelect<T>;
template<typename T> requires Comparable<T>
QuickSelect(vector<T>) -> QuickSelect<T>;
template<typename T, size_t SIZE> requires Comparable<T>
QuickSelect(array<T, SIZE>) -> QuickSelect<T>;
template<typename T> requires Comparable<T>
QuickSelect(T a[]) -> QuickSelect<T>;
template<typename T> requires Comparable<T>
QuickSelect(span<T>, bool reverse) -> QuickSelect<T>;
template<typename T> requires Comparable<T>
QuickSelect(vector<T>, bool reverse) -> QuickSelect<T>;
template<typename T, size_t SIZE> requires Comparable<T>
QuickSelect(array<T, SIZE>, bool reverse) -> QuickSelect<T>;
template<typename T> requires Comparable<T>
QuickSelect(T a[], int length, bool reverse) -> QuickSelect<T>;
#endif //ALGORITHMS_QUICKSELECT_HPP