SoPlex
Loading...
Searching...
No Matches
sorter.h
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the class library */
4/* SoPlex --- the Sequential object-oriented simPlex. */
5/* */
6/* Copyright (c) 1996-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SoPlex; see the file LICENSE. If not email to soplex@zib.de. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file sorter.h
26 * @brief Generic QuickSort implementation.
27 */
28#ifndef _SORTER_H_
29#define _SORTER_H_
30
31#include <assert.h>
32
33namespace soplex
34{
35#define SOPLEX_SHELLSORTMAX 25
36
37/** shell-sort an array of data elements; use it only for arrays smaller than 25 entries */
38template < class T, class COMPARATOR >
39void SPxShellsort(T* keys, int end, COMPARATOR& compare, int start = 0)
40{
41 static const int incs[3] = {1, 5, 19}; // sequence of increments
42
43 assert(start >= 0);
44 assert(end >= start);
45
46 for(int k = 2; k >= 0; --k)
47 {
48 const int h = incs[k];
49
50 for(int i = start + h; i <= end; ++i)
51 {
52 if(compare(keys[i], keys[i - h]) < 0)
53 {
54 const T tmp = keys[i];
55 int j = i - h;
56
57 do
58 {
59 keys[j + h] = keys[j];
60 j -= h;
61 }
62 while(j >= start && compare(tmp, keys[j]) < 0);
63
64 keys[j + h] = tmp;
65 }
66 }
67 }
68}
69
70
71/// Generic QuickSort implementation.
72/** This template function sorts an array \p t holding \p n elements of
73 type T using \p compare for comparisons. Class COMPARATOR must provide
74 an overloaded operator()(const T& t1,const T& t2) which returns
75 - < 0, if \p t1 is to appear before \p t2,
76 - = 0, if \p t1 and \p t2 can appear in any order, or
77 - > 0, if \p t1 is to appear after \p t2.
78*/
79template < class T, class COMPARATOR >
80void SPxQuicksort(T* keys, int end, COMPARATOR& compare, int start = 0, bool type = true)
81{
82 assert(start >= 0);
83 assert(end >= start);
84
85 /* nothing to sort for at most one element */
86 if(end - start <= 1)
87 return;
88
89 /* reduce end position to last element index */
90 --end;
91
92 /* use quick-sort for long lists */
93 while(end - start >= SOPLEX_SHELLSORTMAX)
94 {
95 const int mid = start + (end - start) / 2; // avoid overflowing (start + end) / 2
96 const T pivotkey = keys[mid];
97 int lo = start;
98 int hi = end;
99
100 for(;;)
101 {
102 if(type)
103 {
104 while(compare(keys[lo], pivotkey) < 0)
105 ++lo;
106
107 while(hi > start && compare(keys[hi], pivotkey) >= 0)
108 --hi;
109 }
110 else
111 {
112 while(lo < end && compare(pivotkey, keys[lo]) >= 0)
113 ++lo;
114
115 while(compare(pivotkey, keys[hi]) < 0)
116 --hi;
117 }
118
119 if(lo >= hi)
120 break;
121
122 const T tmp = keys[lo];
123 keys[lo] = keys[hi];
124 keys[hi] = tmp;
125
126 ++lo;
127 --hi;
128 }
129
130 assert((hi == lo - 1) || (type && hi == start) || (!type && lo == end));
131
132 /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
133 if(type)
134 {
135 while(lo < end && compare(pivotkey, keys[lo]) >= 0)
136 ++lo;
137
138 /* make sure that we have at least one element in the smaller partition */
139 if(lo == start)
140 {
141 /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
142 assert(compare(keys[mid], pivotkey) == 0);
143
144 const T tmp = keys[lo];
145 keys[lo] = keys[mid];
146 keys[mid] = tmp;
147
148 ++lo;
149 }
150 }
151 else
152 {
153 while(hi > start && compare(keys[hi], pivotkey) >= 0)
154 --hi;
155
156 /* make sure that we have at least one element in the smaller partition */
157 if(hi == end)
158 {
159 /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
160 assert(compare(keys[mid], pivotkey) == 0);
161
162 const T tmp = keys[hi];
163 keys[hi] = keys[mid];
164 keys[mid] = tmp;
165
166 --hi;
167 }
168 }
169
170 /* sort the smaller partition by a recursive call, sort the larger part without recursion */
171 if(hi - start <= end - lo)
172 {
173 /* sort [start,hi] with a recursive call */
174 if(start < hi)
175 SPxQuicksort(keys, hi + 1, compare, start, !type);
176
177 /* now focus on the larger part [lo,end] */
178 start = lo;
179 }
180 else
181 {
182 if(lo < end)
183 SPxQuicksort(keys, end + 1, compare, lo, !type);
184
185 /* now focus on the larger part [start,hi] */
186 end = hi;
187 }
188
189 type = !type;
190 }
191
192 /* use shell sort on the remaining small list */
193 if(end - start >= 1)
194 SPxShellsort(keys, end, compare, start);
195
196#ifdef CHECK_SORTING
197
198 for(int i = start; i < end; ++i)
199 assert(compare(keys[i], keys[i + 1]) <= 0);
200
201#endif
202}
203
204
205/**@brief Generic implementation of Partial QuickSort.
206 *
207 * This template function sorts an array \p t holding \p n elements of
208 * type T partially using \p compare for comparisons, i.e. ensures that
209 * the \p size smallest elements are sorted to the front.
210 *
211 * Class COMPARATOR must provide an overloaded
212 * operator()(const T& t1,const T& t2) which returns
213 * - < 0, if \p t1 is to appear before \p t2,
214 * - = 0, if \p t1 and \p t2 can appear in any order, or
215 * - > 0, if \p t1 is to appear after \p t2.
216 *
217 * @param keys array of elements to be sorted between index start and end
218 * @param compare comparator
219 * @param start index of first element in range to be sorted
220 * @param end index of last element in range to be sorted plus 1
221 * @param size guaranteed number of additionally sorted elements
222 * @param start2 auxiliary start index of sub range used for recursive call (deprecated)
223 * @param end2 auxiliary end index of sub range used for recursive call (disabled)
224 * @param type type of sorting, to be more flexible on degenerated cases
225 * @return index of last element in range sorted plus 1
226 */
227template < class T, class COMPARATOR >
228int SPxQuicksortPart(T* keys, COMPARATOR& compare, int start, int end, int size, int start2 = 0,
229 int end2 = 0, bool type = true)
230{
231 assert(start >= 0);
232 assert(end >= start);
233 assert(start2 <= end);
234 assert(end2 <= end);
235
236 /* nothing to sort for at most one element */
237 if(end - start <= 1)
238 return end;
239
240 /* we assume that range {start, ..., start2-1} already contains start2-start smallest elements in sorted order */
241#ifdef CHECK_SORTING
242
243 for(int i = start; i < start2 - 1; ++i)
244 assert(compare(keys[i], keys[i + 1]) <= 0);
245
246#endif
247
248 /* skip sorted prefix */
249 if(start < start2)
250 start = start2;
251
252 /* the two smaller/larger sub-ranges are processed by looping instead of recursing */
253 for(;;)
254 {
255 /* if all remaining elements should be sorted, we simply call standard quicksort */
256 if(start >= end - size - 1)
257 {
258 SPxQuicksort(keys, end, compare, start, type);
259 return end;
260 }
261
262 /* reduce end position to last element index */
263 --end;
264
265 /* select pivot element */
266 const int mid = start + (end - start) / 2; // avoid overflowing (start + end) / 2
267 const T pivotkey = keys[mid];
268 int lo = start;
269 int hi = end;
270
271 for(;;)
272 {
273 if(type)
274 {
275 while(compare(keys[lo], pivotkey) < 0)
276 ++lo;
277
278 while(hi > start && compare(keys[hi], pivotkey) >= 0)
279 --hi;
280 }
281 else
282 {
283 while(lo < end && compare(pivotkey, keys[lo]) >= 0)
284 ++lo;
285
286 while(compare(pivotkey, keys[hi]) < 0)
287 --hi;
288 }
289
290 if(lo >= hi)
291 break;
292
293 const T tmp = keys[lo];
294 keys[lo] = keys[hi];
295 keys[hi] = tmp;
296
297 ++lo;
298 --hi;
299 }
300
301 assert((hi == lo - 1) || (type && hi == start) || (!type && lo == end));
302
303 /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
304 if(type)
305 {
306 while(lo < end && compare(pivotkey, keys[lo]) >= 0)
307 ++lo;
308
309 /* make sure that we have at least one element in the smaller partition */
310 if(lo == start)
311 {
312 /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
313 assert(compare(keys[mid], pivotkey) == 0);
314
315 const T tmp = keys[lo];
316 keys[lo] = keys[mid];
317 keys[mid] = tmp;
318
319 ++lo;
320 }
321 }
322 else
323 {
324 while(hi > start && compare(keys[hi], pivotkey) >= 0)
325 --hi;
326
327 /* make sure that we have at least one element in the smaller partition */
328 if(hi == end)
329 {
330 /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
331 assert(compare(keys[mid], pivotkey) == 0);
332
333 const T tmp = keys[hi];
334 keys[hi] = keys[mid];
335 keys[mid] = tmp;
336
337 --hi;
338 }
339 }
340
341#ifdef CHECK_SORTING
342
343 for(int i = start; i < lo; ++i)
344 assert(compare(keys[i], pivotkey) <= 0);
345
346#endif
347
348 /* if we only need to sort less than half of the "<" part, use partial sort again */
349 if(start <= hi - 2 * size)
350 {
351 end = hi + 1;
352 type = !type;
353 }
354 /* otherwise, and if we do not need to sort the ">" part, use standard quicksort on the "<" part */
355 else if(start <= lo - size)
356 {
357 SPxQuicksort(keys, hi + 1, compare, start, !type);
358 return lo;
359 }
360 /* otherwise we have to sort the "<" part fully (use standard quicksort) and the ">" part partially */
361 else
362 {
363 SPxQuicksort(keys, hi + 1, compare, start, !type);
364 size += start - lo;
365 ++end;
366 start = lo;
367 type = !type;
368 }
369
370 /* nothing to sort for at most one element */
371 if(end - start <= 1)
372 return end;
373 }
374}
375
376} // namespace soplex
377#endif // _SORTER_H_
Everything should be within this namespace.
void SPxShellsort(T *keys, int end, COMPARATOR &compare, int start=0)
Definition sorter.h:39
int SPxQuicksortPart(T *keys, COMPARATOR &compare, int start, int end, int size, int start2=0, int end2=0, bool type=true)
Generic implementation of Partial QuickSort.
Definition sorter.h:228
void SPxQuicksort(T *keys, int end, COMPARATOR &compare, int start=0, bool type=true)
Generic QuickSort implementation.
Definition sorter.h:80
#define SOPLEX_SHELLSORTMAX
Definition sorter.h:35