AceSorting  1.0.0
Sorting algorithms for Arduino including Bubble Sort, Insertion Sort, Selection Sort, Shell Sort (3 versions), Comb Sort (4 versions), Quick Sort (3 versions)
quickSort.h
Go to the documentation of this file.
1 /*
2 MIT License
3 
4 Copyright (c) 2021 Brian T. Park
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 
32 #ifndef ACE_SORTING_QUICK_SORT_H
33 #define ACE_SORTING_QUICK_SORT_H
34 
35 #include "swap.h"
36 
37 #if ! defined(ACE_SORTING_DIRECT_QUICK_SORT)
38 
48  #define ACE_SORTING_DIRECT_QUICK_SORT 1
49 #endif
50 
51 namespace ace_sorting {
52 
62 #if ACE_SORTING_DIRECT_QUICK_SORT
63 template <typename T>
64 void quickSortMiddle(T data[], uint16_t n) {
65  if (n <= 1) return;
66 
67  T pivot = data[n / 2];
68  T* left = data;
69  T* right = data + n - 1;
70 
71  while (left <= right) {
72  if (*left < pivot) {
73  left++;
74  } else if (pivot < *right) {
75  right--;
76  } else {
77  swap(*left, *right);
78  left++;
79  right--;
80  }
81  }
82 
83  quickSortMiddle(data, right - data + 1);
84  quickSortMiddle(left, data + n - left);
85 }
86 #else
87 template <typename T>
88 void quickSortMiddle(T data[], uint16_t n) {
89  // This lambda expression does not perform any captures, so the compiler ought
90  // to be able to optimize and inline the less-than expression. However, the
91  // optimization does not seem to work, probably because of the recursive call
92  // into itself. So we set ACE_SORTING_DIRECT_QUICK_SORT=1 to use the direct
93  // inlined version.
94  auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; };
95  quickSortMiddle(data, n, lessThan);
96 }
97 #endif
98 
106 template <typename T, typename F>
107 void quickSortMiddle(T data[], uint16_t n, F&& lessThan) {
108  if (n <= 1) return;
109 
110  T pivot = data[n / 2];
111  T* left = data;
112  T* right = data + n - 1;
113 
114  while (left <= right) {
115  if (lessThan(*left, pivot)) {
116  left++;
117  } else if (lessThan(pivot, *right)) {
118  right--;
119  } else {
120  swap(*left, *right);
121  left++;
122  right--;
123  }
124  }
125 
126  quickSortMiddle(data, right - data + 1, lessThan);
127  quickSortMiddle(left, data + n - left, lessThan);
128 }
129 
130 //-----------------------------------------------------------------------------
131 
141 #if ACE_SORTING_DIRECT_QUICK_SORT
142 template <typename T>
143 void quickSortMedian(T data[], uint16_t n) {
144  if (n <= 1) return;
145 
146  // Select the median of data[low], data[mid], and data[high] as the estimate
147  // of the ideal pivot. Don't swap (low, mid) or (mid, high) (compare that
148  // quickSortMedianSwapped()) to save flash memory. They will get swapped in
149  // the partitioning while-loop below.
150  uint16_t mid = n / 2;
151  T pivot = data[mid];
152  if (data[n - 1] < data[0]) {
153  swap(data[0], data[n - 1]);
154  }
155  if (pivot < data[0]) {
156  pivot = data[0];
157  } else if (data[n - 1] < pivot) {
158  pivot = data[n - 1];
159  }
160 
161  T* left = data;
162  T* right = data + n - 1;
163 
164  while (left <= right) {
165  if (*left < pivot) {
166  left++;
167  } else if (pivot < *right) {
168  right--;
169  } else {
170  swap(*left, *right);
171  left++;
172  right--;
173  }
174  }
175 
176  quickSortMedian(data, right - data + 1);
177  quickSortMedian(left, data + n - left);
178 }
179 #else
180 template <typename T>
181 void quickSortMedian(T data[], uint16_t n) {
182  // This lambda expression does not perform any captures, so the compiler will
183  // optimize and inline the less-than expression.
184  auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; };
185  quickSortMedian(data, n, lessThan);
186 }
187 #endif
188 
196 template <typename T, typename F>
197 void quickSortMedian(T data[], uint16_t n, F&& lessThan) {
198  if (n <= 1) return;
199 
200  // Select the median of data[low], data[mid], and data[high] as the estimate
201  // of the ideal pivot. Don't swap (low, mid) or (mid, high) (compare that
202  // quickSortMedianSwapped()) to save flash memory. They will get swapped in
203  // the partitioning while-loop below.
204  uint16_t mid = n / 2;
205  T pivot = data[mid];
206  if (lessThan(data[n - 1], data[0])) {
207  swap(data[0], data[n - 1]);
208  }
209  if (lessThan(pivot, data[0])) {
210  pivot = data[0];
211  } else if (lessThan(data[n - 1], pivot)) {
212  pivot = data[n - 1];
213  }
214 
215  T* left = data;
216  T* right = data + n - 1;
217 
218  while (left <= right) {
219  if (lessThan(*left, pivot)) {
220  left++;
221  } else if (lessThan(pivot, *right)) {
222  right--;
223  } else {
224  swap(*left, *right);
225  left++;
226  right--;
227  }
228  }
229 
230  quickSortMedian(data, right - data + 1, lessThan);
231  quickSortMedian(left, data + n - left, lessThan);
232 }
233 
234 //-----------------------------------------------------------------------------
235 
245 #if ACE_SORTING_DIRECT_QUICK_SORT
246 template <typename T>
247 void quickSortMedianSwapped(T data[], uint16_t n) {
248  if (n <= 1) return;
249 
250  // Select the median of data[low], data[mid], and data[high] as the estimate
251  // of the ideal pivot. In the process, the (low, mid, high) become sorted.
252  uint16_t mid = n / 2;
253  T pivot = data[mid];
254  if (data[n - 1] < data[0]) {
255  swap(data[0], data[n - 1]);
256  }
257  if (pivot < data[0]) {
258  swap(data[0], data[mid]);
259  } else if (data[n - 1] < pivot) {
260  swap(data[mid], data[n - 1]);
261  }
262  pivot = data[mid];
263 
264  // We can skip the low and high because they are already sorted.
265  T* left = data + 1;
266  T* right = data + n - 2;
267 
268  while (left <= right) {
269  if (*left < pivot) {
270  left++;
271  } else if (pivot < *right) {
272  right--;
273  } else {
274  swap(*left, *right);
275  left++;
276  right--;
277  }
278  }
279 
280  quickSortMedianSwapped(data, right - data + 1);
281  quickSortMedianSwapped(left, data + n - left);
282 }
283 #else
284 template <typename T>
285 void quickSortMedianSwapped(T data[], uint16_t n) {
286  // This lambda expression does not perform any captures, so the compiler will
287  // optimize and inline the less-than expression.
288  auto&& lessThan = [](const T& a, const T& b) -> bool { return a < b; };
289  quickSortMedianSwapped(data, n, lessThan);
290 }
291 #endif
292 
300 template <typename T, typename F>
301 void quickSortMedianSwapped(T data[], uint16_t n, F&& lessThan) {
302  if (n <= 1) return;
303 
304  // Select the median of data[low], data[mid], and data[high] as the estimate
305  // of the ideal pivot. In the process, the (low, mid, high) become sorted.
306  uint16_t mid = n / 2;
307  T pivot = data[mid];
308  if (lessThan(data[n - 1], data[0])) {
309  swap(data[0], data[n - 1]);
310  }
311  if (lessThan(pivot, data[0])) {
312  swap(data[0], data[mid]);
313  } else if (lessThan(data[n - 1], pivot)) {
314  swap(data[mid], data[n - 1]);
315  }
316  pivot = data[mid];
317 
318  // We can skip the low and high because they are already sorted.
319  T* left = data + 1;
320  T* right = data + n - 2;
321 
322  while (left <= right) {
323  if (lessThan(*left, pivot)) {
324  left++;
325  } else if (lessThan(pivot, *right)) {
326  right--;
327  } else {
328  swap(*left, *right);
329  left++;
330  right--;
331  }
332  }
333 
334  quickSortMedianSwapped(data, right - data + 1, lessThan);
335  quickSortMedianSwapped(left, data + n - left, lessThan);
336 }
337 
338 }
339 
340 #endif
ace_sorting::quickSortMedianSwapped
void quickSortMedianSwapped(T data[], uint16_t n)
Same as quickSortMedian(), but swap the low and high so that low, mid, and high elements become sorte...
Definition: quickSort.h:247
swap.h
ace_sorting::swap
void swap(T &a, T &b)
Swap the parameters.
Definition: swap.h:41
ace_sorting::quickSortMiddle
void quickSortMiddle(T data[], uint16_t n)
Quick sort using Hoare's original partition where the pivot is the middle of the array.
Definition: quickSort.h:64
ace_sorting::quickSortMedian
void quickSortMedian(T data[], uint16_t n)
Quick sort using Sedgewick's recommendation of using the median of low, middle and high.
Definition: quickSort.h:143