1use crate::vector::FocusMut;
6use rand_core::{RngCore, SeedableRng};
7use std::cmp::Ordering;
8use std::mem;
9
10fn gen_range<R: RngCore>(rng: &mut R, min: usize, max: usize) -> usize {
11 let range = max - min;
12 min + (rng.next_u64() as usize % range)
13}
14
15fn do_quicksort<A, F, R>(vector: FocusMut<'_, A>, cmp: &F, rng: &mut R)
23where
24 A: Clone,
25 F: Fn(&A, &A) -> Ordering,
26 R: RngCore,
27{
28 if vector.len() <= 1 {
29 return;
30 }
31
32 let pivot_index = gen_range(rng, 0, vector.len());
34 let (mut first, mut rest) = vector.split_at(1);
35
36 if pivot_index > 0 {
37 mem::swap(rest.index_mut(pivot_index - 1), first.index_mut(0));
38 }
39 let pivot_item = first.index(0);
41
42 let mut less_count = 0;
44 let mut equal_count = 0;
45
46 for index in 0..rest.len() {
47 let item = rest.index(index);
48 let comp = cmp(item, pivot_item);
49 match comp {
50 Ordering::Less => less_count += 1,
51 Ordering::Equal => equal_count += 1,
52 Ordering::Greater => {}
53 }
54 }
55
56 if less_count == 0 {
59 do_quicksort(rest, cmp, rng);
60 return;
61 }
62
63 less_count -= 1;
67 equal_count += 1;
68 let first_item = first.index_mut(0);
69 mem::swap(first_item, rest.index_mut(less_count));
70 for index in 0..rest.len() {
71 if index == less_count {
72 continue;
75 }
76 let rest_item = rest.index_mut(index);
77 if cmp(rest_item, first_item) == Ordering::Less {
78 mem::swap(first_item, rest_item);
79 }
80 }
81
82 let (remaining, mut greater_focus) = rest.split_at(less_count + equal_count);
84 let (mut less_focus, mut equal_focus) = remaining.split_at(less_count);
85
86 let mut less_position = 0;
87 let mut equal_position = 0;
88 let mut greater_position = 0;
89
90 while less_position != less_focus.len() || greater_position != greater_focus.len() {
91 let mut equal_swap_side = None;
93 let equal_item = equal_focus.index(equal_position);
94
95 while less_position != less_focus.len() {
97 let less_item = less_focus.index(less_position);
98 match cmp(less_item, equal_item) {
99 Ordering::Equal => {
100 equal_swap_side = Some(Ordering::Less);
101 break;
102 }
103 Ordering::Greater => {
104 break;
105 }
106 _ => {}
107 }
108 less_position += 1;
109 }
110
111 while greater_position != greater_focus.len() {
113 let greater_item = greater_focus.index(greater_position);
114 match cmp(greater_item, equal_item) {
115 Ordering::Less => break,
116 Ordering::Equal => {
117 equal_swap_side = Some(Ordering::Greater);
118 break;
119 }
120 _ => {}
121 }
122 greater_position += 1;
123 }
124
125 if let Some(swap_side) = equal_swap_side {
126 let item = if swap_side == Ordering::Less {
128 less_focus.index_mut(less_position)
129 } else {
130 greater_focus.index_mut(greater_position)
131 };
132
133 while cmp(item, equal_focus.index(equal_position)) == Ordering::Equal {
135 equal_position += 1;
136 }
137
138 mem::swap(item, equal_focus.index_mut(equal_position));
141 } else if less_position != less_focus.len() && greater_position != greater_focus.len() {
142 debug_assert_ne!(
146 cmp(
147 less_focus.index(less_position),
148 equal_focus.index(equal_position)
149 ),
150 Ordering::Equal
151 );
152 debug_assert_ne!(
153 cmp(
154 greater_focus.index(greater_position),
155 equal_focus.index(equal_position)
156 ),
157 Ordering::Equal
158 );
159 mem::swap(
160 less_focus.index_mut(less_position),
161 greater_focus.index_mut(greater_position),
162 );
163 less_position += 1;
164 greater_position += 1;
165 }
166 }
167
168 do_quicksort(less_focus, cmp, rng);
170 if !greater_focus.is_empty() {
171 do_quicksort(greater_focus, cmp, rng);
172 }
173}
174
175pub(crate) fn quicksort<A, F>(vector: FocusMut<'_, A>, cmp: &F)
176where
177 A: Clone,
178 F: Fn(&A, &A) -> Ordering,
179{
180 let mut rng = rand_xoshiro::Xoshiro256Plus::seed_from_u64(0);
181 do_quicksort(vector, cmp, &mut rng);
182}
183
184#[cfg(test)]
185mod test {
186 use super::*;
187 use crate::test::is_sorted;
188 use crate::vector::proptest::vector;
189 use ::proptest::num::i32;
190 use ::proptest::proptest;
191
192 proptest! {
193 #[test]
194 fn test_quicksort(ref input in vector(i32::ANY, 0..10000)) {
195 let mut vec = input.clone();
196 let len = vec.len();
197 if len > 1 {
198 quicksort(vec.focus_mut(), &Ord::cmp);
199 }
200 assert!(is_sorted(vec));
201 }
202 }
203}