-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathQuick.h
126 lines (110 loc) · 3.34 KB
/
Quick.h
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
#ifndef CH2_QUICK_H
#define CH2_QUICK_H
#include <vector>
#include <random>
#include <iostream>
#include <algorithm>
#include <stdexcept>
using std::vector;
using std::swap;
using std::cout;
using std::endl;
using std::to_string;
using std::random_device;
using std::mt19937;
using std::shuffle;
using std::runtime_error;
random_device rd;
mt19937 g(rd());
/**
* The {@code Quick} class provides static methods for sorting an
* array and selecting the ith smallest element in an array using quicksort.
* <p>
* For additional documentation,
* see <a href="https://algs4.cs.princeton.edu/23quick">Section 2.3</a> of
* <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
*
* @author Robert Sedgewick
* @author Kevin Wayne
*/
class Quick {
public:
// This class should not be instantiated.
Quick() = delete;
/**
* Rearranges the array in ascending order, using the natural order.
* @param a the array to be sorted
*/
template<typename T>
static void sort(vector<T> &a) {
shuffle(a.begin(), a.end(), g);
sort(a, 0, a.size() - 1);
}
/**
* Rearranges the array 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 a the array
* @param k the rank of the key
* @return the key of rank {@code k}
* @throws IllegalArgumentException unless {@code 0 <= k < a.length}
*/
template<typename T>
static T select(vector<T> &a, int k) {
if (k < 0 || k >= a.size()) {
throw runtime_error("index is not between 0 and " + to_string(a.size()) + ": " + to_string(k));
}
shuffle(a.begin(), a.end(), g);
int lo = 0, hi = a.size() - 1;
while (hi > lo) {
int i = partition(a, lo, hi);
if (i > k) hi = i - 1;
else if (i < k) lo = i + 1;
else return a[i];
}
return a[lo];
}
// print array to standard output
template<typename T>
static void show(vector<T> &a) {
for (int i = 0; i < a.size(); i++) {
cout << a[i] << endl;
}
}
private:
// quicksort the subarray from a[lo] to a[hi]
template<typename T>
static void sort(vector<T> &a, int lo, int hi) {
if (hi <= lo) return;
int j = partition(a, lo, hi);
sort(a, lo, j - 1);
sort(a, j + 1, hi);
}
// partition the subarray a[lo..hi] so that a[lo..j-1] <= a[j] <= a[j+1..hi]
// and return the index j.
template<typename T>
static int partition(vector<T> &a, int lo, int hi) {
int i = lo;
int j = hi + 1;
T v = a[lo];
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;
swap(a[i], a[j]);
}
// put partitioning item v at a[j]
swap(a[lo], a[j]);
// now, a[lo .. j-1] <= a[j] <= a[j+1 .. hi]
return j;
}
};
#endif //CH2_QUICK_H