Scippy

SoPlex

Sequential object-oriented simPlex

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