HermesCommon  2.0
qsort.cpp
Go to the documentation of this file.
1 // This file is part of HermesCommon.
2 //
3 // Hermes2D is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // Hermes2D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Hermes2D. If not, see <http://www.gnu.org/licenses/>.
19 #include "qsort.h"
20 #include <limits.h>
21 #include <algorithm>
22 #include <stdlib.h>
23 
24 #define SWAP(a, b) { int c = *(a); *(a) = *(b); *(b) = c; }
25 
26 #define MAX_THRESH 4
27 
28 typedef struct
29 {
30  int *lo;
31  int *hi;
32 } stack_node;
33 
34 #define STACK_SIZE (CHAR_BIT * sizeof(size_t))
35 #define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
36 #define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
37 #define STACK_NOT_EMPTY (stack < top)
38 
39 #define min(x, y) ((x) < (y) ? (x) : (y))
40 
42 void qsort_int(int* pbase, size_t total_elems)
43 {
44  register int *base_ptr = pbase;
45 
46  if(total_elems == 0) return;
47 
48  if(total_elems > MAX_THRESH)
49  {
50  int *lo = base_ptr;
51  int *hi = lo + total_elems - 1;
52  stack_node stack[STACK_SIZE];
53  stack_node *top = stack;
54 
55  PUSH(NULL, NULL);
56 
57  while (STACK_NOT_EMPTY)
58  {
59  int *left_ptr;
60  int *right_ptr;
61 
62  // Select median value from among LO, MID, and HI. Rearrange
63  // LO and HI so the three values are sorted. This lowers the
64  // probability of picking a pathological pivot value and
65  // skips a comparison for both the LEFT_PTR and RIGHT_PTR in
66  // the while loops.
67 
68  int *mid = lo + ((hi - lo) >> 1);
69 
70  if(*mid < *lo)
71  SWAP (mid, lo);
72  if(*hi < *mid)
73  SWAP (mid, hi)
74  else
75  goto jump_over;
76  if(*mid < *lo)
77  SWAP(mid, lo);
78 jump_over:
79 
80  left_ptr = lo + 1;
81  right_ptr = hi - 1;
82 
83  // Here's the famous ``collapse the walls'' section of quicksort.
84  // Gotta like those tight inner loops! They are the main reason
85  // that this algorithm runs much faster than others.
86  do
87  {
88  while (*left_ptr < *mid)
89  left_ptr++;
90 
91  while (*mid < *right_ptr)
92  right_ptr--;
93 
94  if(left_ptr < right_ptr)
95  {
96  SWAP(left_ptr, right_ptr);
97  if(mid == left_ptr)
98  mid = right_ptr;
99  else if(mid == right_ptr)
100  mid = left_ptr;
101  left_ptr++;
102  right_ptr--;
103  }
104  else if(left_ptr == right_ptr)
105  {
106  left_ptr++;
107  right_ptr--;
108  break;
109  }
110  }
111  while (left_ptr <= right_ptr);
112 
113  // Set up pointers for next iteration. First determine whether
114  // left and right partitions are below the threshold size. If so,
115  // ignore one or both. Otherwise, push the larger partition's
116  // bounds on the stack and continue sorting the smaller one.
117 
118  if((size_t) (right_ptr - lo) <= MAX_THRESH)
119  {
120  if((size_t) (hi - left_ptr) <= MAX_THRESH)
121  // Ignore both small partitions.
122  POP(lo, hi);
123  else
124  // Ignore small left partition.
125  lo = left_ptr;
126  }
127  else if((size_t) (hi - left_ptr) <= MAX_THRESH)
128  // Ignore small right partition.
129  hi = right_ptr;
130  else if((right_ptr - lo) > (hi - left_ptr))
131  {
132  // Push larger left partition indices.
133  PUSH(lo, right_ptr);
134  lo = left_ptr;
135  }
136  else
137  {
138  // Push larger right partition indices.
139  PUSH(left_ptr, hi);
140  hi = right_ptr;
141  }
142  }
143  }
144 
145  // Once the BASE_PTR array is partially sorted by quicksort the rest
146  // is completely sorted using insertion sort, since this is efficient
147  // for partitions below MAX_THRESH size. BASE_PTR points to the beginning
148  // of the array to sort, and END_PTR points at the very last element in
149  // the array (*not* one beyond it!).
150  {
151  int *const end_ptr = base_ptr + total_elems - 1;
152  int *tmp_ptr = base_ptr;
153  int *thresh = min(end_ptr, base_ptr + MAX_THRESH);
154  register int *run_ptr;
155 
156  // Find smallest element in first threshold and place it at the
157  // array's beginning. This is the smallest array element,
158  // and the operation speeds up insertion sort's inner loop.
159 
160  for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++)
161  if(*run_ptr < *tmp_ptr)
162  tmp_ptr = run_ptr;
163 
164  if(tmp_ptr != base_ptr)
165  SWAP(tmp_ptr, base_ptr);
166 
167  // Insertion sort, running from left-hand-side up to right-hand-side.
168  run_ptr = base_ptr + 1;
169  while (++run_ptr <= end_ptr)
170  {
171  tmp_ptr = run_ptr - 1;
172  while (*run_ptr < *tmp_ptr)
173  tmp_ptr--;
174 
175  tmp_ptr++;
176  if(tmp_ptr != run_ptr)
177  {
178  int c = *run_ptr;
179  register int *hi, *lo;
180 
181  for (hi = lo = run_ptr; --lo >= tmp_ptr; hi = lo)
182  *hi = *lo;
183  *hi = c;
184  }
185  }
186  }
187 }