feisty meow concerns codebase 2.140
sorts.h
Go to the documentation of this file.
1#ifndef ASSORTED_SORTS_GROUP
2#define ASSORTED_SORTS_GROUP
3
5// Name : sorts
6// Author : Chris Koeritz
8// Copyright (c) 1991-$now By Author. This program is free software; you can
9// redistribute it and/or modify it under the terms of the GNU General Public
10// License as published by the Free Software Foundation:
11// http://www.gnu.org/licenses/gpl.html
12// or under the terms of the GNU Library license:
13// http://www.gnu.org/licenses/lgpl.html
14// at your preference. Those licenses describe your legal rights to this
15// software, and no other rights or warranties apply.
16// Please send updates for this code to: fred@gruntose.com -- Thanks, fred.
18
19#include <mathematics/chaos.h>
20
21#include <system_helper.h>
22
23namespace algorithms {
24
25 /*
26 * general considerations:
27 *
28 * + Generic objects to be sorted must support comparison operators.
29 *
30 * + If the "reverse" flag is true, the arrays will be sorted in reverse order.
31 * Reverse order here means "descending", such that array element i is always greater than or equal to array element i+1.
32 * Normal order is "ascending", such that element i is always less than or equal to array element i+1.
33 *
34 */
35
37 template<class type>
38 basis::astring dump_list(type v[], int size)
39 {
41 for (int i = 0; i < size; i++) {
42 ret += basis::a_sprintf("%d ", (int)v[i]);
43 }
44 return ret;
45 }
46
48
54 template<class type>
55 void shell_sort(type v[], int n, bool reverse = false)
56 {
57 type temp;
58 int gap, i, j;
59 /* the gap sizes decrease quadratically(?). they partition the array of
60 * items that need to be sorted into first two groups, then four, then
61 * eight, etc. the inner loop iterates across each gap's worth of the array.
62 */
63 for (gap = n / 2; gap > 0; gap /= 2) {
64 // the i indexed loop is the base for where the comparisons are made in
65 // the j indexed loop. it makes sure that each item past the edge of
66 // the gap sized partition gets considered.
67 for (i = gap; i < n; i++) {
68 // the j indexed loop looks at the values in our current gap and ensures
69 // that they are in sorted order.
70 if (!reverse) {
71 // normal ordering.
72 for (j = i - gap; j >= 0 && v[j] > v[j + gap]; j = j - gap) {
73 // swap the elements that are disordered.
74 temp = v[j];
75 v[j] = v[j + gap];
76 v[j + gap] = temp;
77 }
78 } else {
79 // reversed ordering.
80 for (j = i - gap; j >= 0 && v[j] < v[j + gap]; j = j - gap) {
81 // swap the elements that are disordered.
82 temp = v[j];
83 v[j] = v[j + gap];
84 v[j + gap] = temp;
85 }
86 }
87 }
88 }
89 }
90
92
98 template<class type>
100 {
101 basis::array<type> to_return;
102 // operate until we've consumed both of the arrays.
103 while ((first.length() > 0) || (second.length() > 0)) {
104 if (first.length() <= 0) {
105 // nothing left in first, so use the second.
106 to_return += second[0];
107 second.zap(0, 0);
108 } else if (second.length() <= 0) {
109 to_return += first[0];
110 first.zap(0, 0);
111 } else if ((!reverse && (first[0] <= second[0])) || (reverse && (first[0] >= second[0]))) {
112 // the first list has a better value to add next.
113 to_return += first[0];
114 first.zap(0, 0);
115 } else {
116 // the second list has a better value to add next.
117 to_return += second[0];
118 second.zap(0, 0);
119 }
120 }
121 return to_return;
122 }
123
130 template<class type>
131 basis::array<type> merge_sort(const basis::array<type> &v, bool reverse = false)
132 {
133 if (v.length() <= 1) {
134 return basis::array<type>(v);
135 }
136 int midway = v.length() / 2;
137 basis::array<type> firstPart = merge_sort(v.subarray(0, midway - 1), reverse);
138 basis::array<type> secondPart = merge_sort(v.subarray(midway, v.length() - 1), reverse);
139 return merge(firstPart, secondPart, reverse);
140 }
141
143
154//hmmm: move this class out to basis?.
155 template<class type>
156 class heap
157 {
158 public:
159 heap(type to_sort[], int n, bool reverse)
160 {
161 _total = n;
162 _reverse = reverse;
163 _heapspace = to_sort;
164 heapify();
165 }
166
168 void swap_values(int a, int b)
169 {
170 type temp = _heapspace[a];
171 _heapspace[a] = _heapspace[b];
172 _heapspace[b] = temp;
173 }
174
176
177 int parent_index(int i)
178 {
179 return i / 2; // rely on integer division to shave off remainder.
180 }
181
183 int left_child(int i)
184 {
185 return 2 * i + 1;
186 }
187
189 int right_child(int i)
190 {
191 return 2 * i + 2;
192 }
193
195 void heapify()
196 {
197 int start = parent_index(_total - 1);
198 // iterate from the back of the array towards the front, so depth-first.
199 while (start >= 0) {
200 // sift down the node at the index 'start' such that all nodes below it are heapified.
201 sift_down(start, _total - 1);
202 start--; // move the start upwards towards the root.
203 }
204 }
205
206 void sift_down(int start, int end)
207 {
208 int root = start;
209
210 // while the current root still has a kid...
211 while (left_child(root) <= end) {
212 int child = left_child(root);
213 // figure out which child to swap with.
214 int swap = root;
215 // check if the root should be swapped with this kid.
216 if ((!_reverse && (_heapspace[swap] > _heapspace[child]))
217 || (_reverse && (_heapspace[swap] < _heapspace[child])))
218 {
219 swap = child;
220 }
221 // check if the other child should be swapped with the root or left kid.
222 if ((child + 1 <= end)
223 && ((!_reverse && (_heapspace[swap] > _heapspace[child + 1]))
224 || (_reverse && (_heapspace[swap] < _heapspace[child + 1]))))
225 {
226 swap = child + 1;
227 }
228 if (swap == root) {
229 // the root has the largest (or smallest) element, so we're done.
230 return;
231 } else {
232 swap_values(root, swap);
233 root = swap;
234 // repeat to continue sifting down the child now.
235 }
236 }
237 }
238
241 {
242 int end = 1; // start at first child.
243
244 while (end < _total) {
245 // sift down the node at the index 'start' such that all nodes below it are heapified.
246 sift_up(0, end++);
247 }
248 }
249
251 void sift_up(int start, int end)
252 {
253 int child = end;
254 // loop until we hit the starting node, where we're done.
255 while (child > start) {
256 int parent = parent_index(child);
257 if ((!_reverse && (_heapspace[parent] < _heapspace[child]))
258 || (_reverse && (_heapspace[parent] > _heapspace[child])))
259 {
260 swap_values(parent, child);
261 child = parent;
262 // continue sifting at the parent now.
263 } else {
264 // done sorting.
265 return;
266 }
267 }
268 }
269
270 private:
271 bool _reverse; // is the sorting in reverse?
272 int _total; // how many total elements are there?
273 int *_heapspace; // track a pointer to the array.
274 };
275
282 template<class type>
283 void heap_sort(type v[], int n, bool reverse = false)
284 {
285 // reverse the sense of "reverse", since our algorithm expects a normal heap (with largest on top).
286 heap<type> hap(v, n, !reverse);
287
288 int end = n - 1;
289 while (end > 0) {
290 // a[0] is the root and largest value for a normal heap. The swap moves it to the real end of the list and takes it out of consideration.
291 hap.swap_values(end, 0);
292 // reduce the heap size by 1.
293 end--;
294 // that swap ruined the heap property, so re-heapify.
295 hap.sift_down(0, end);
296 }
297 }
298
300
302 template<class type>
303 void swap_values(type array[], int a, int b)
304 {
305 type temp = array[a];
306 array[a] = array[b];
307 array[b] = temp;
308 }
309
310 // hoare's partition implementation.
311 template<class type>
312 int partition(type a[], int start, int end, bool reverse)
313 {
314// printf("before partition: %s\n", dump_list(a + start, end - start + 1).s());
315 int pivot = a[start];
316 int i = start - 1;
317 int j = end + 1;
318 while (true) {
319 do {
320 i++;
321 } while ((!reverse && (a[i] < pivot)) || (reverse && (a[i] > pivot)));
322 do {
323 j--;
324 } while ((!reverse && (a[j] > pivot)) || (reverse && (a[j] < pivot)));
325
326 if (i >= j) {
327// printf("after partition: %s\n", dump_list(a + start, end - start + 1).s());
328 return j;
329 }
330 swap_values(a, i, j);
331 }
332 }
333
335 template<class type>
336 void inner_quick_sort(type v[], int start, int end, bool reverse)
337 {
338 if (start < end) {
339 // figure out where to pivot, and sort both halves around the pivot index.
340 int pivot = partition(v, start, end, reverse);
341 inner_quick_sort(v, start, pivot, reverse);
342 inner_quick_sort(v, pivot + 1, end, reverse);
343 }
344 }
345
352 template <class type>
353 void quick_sort(type v[], int n, bool reverse = false)
354 {
355 inner_quick_sort(v, 0, n - 1, reverse);
356 }
357
359
361 template <class type>
362 void randomize_list(type v[], int n)
363 {
365 for (int i = 0; i < n; i++) {
366 // we will swap with any element that is not prior to the current index; thus we allow
367 // swapping the element with itself and later, but not with anything earlier.
368 int swap_index = randomizer.inclusive(i, n - 1);
369 swap_values(v, i, swap_index);
370 }
371 }
372
373} // namespace.
374
375#endif // outer guard.
376
void alt_heapify()
re-sorts the heapspace to maintain the heap ordering. this uses sift_up.
Definition sorts.h:240
int right_child(int i)
returns the right child of node at position i.
Definition sorts.h:189
heap(type to_sort[], int n, bool reverse)
Definition sorts.h:159
void sift_down(int start, int end)
Definition sorts.h:206
void heapify()
re-sorts the heapspace to maintain the heap ordering.
Definition sorts.h:195
void sift_up(int start, int end)
start is how far up in the heap to sort. end is the node to sift.
Definition sorts.h:251
void swap_values(int a, int b)
swaps the values in the heap stored at positions a and b.
Definition sorts.h:168
int left_child(int i)
returns the left child of node at position i.
Definition sorts.h:183
int parent_index(int i)
get the index of the parent of the node at i.
Definition sorts.h:177
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
Represents a sequential, ordered, contiguous collection of objects.
Definition array.h:54
array subarray(int start, int end) const
Returns the array segment between the indices "start" and "end".
Definition array.h:443
int length() const
Returns the current reported length of the allocated C array.
Definition array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition array.h:769
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
a platform-independent way to acquire random numbers in a specific range.
Definition chaos.h:51
int inclusive(int low, int high) const
< Returns a pseudo-random number r, such that "low" <= r <= "high".
Definition chaos.h:88
void swap_values(type array[], int a, int b)
swaps the values in the array stored at positions a and b.
Definition sorts.h:303
void randomize_list(type v[], int n)
handy method for randomizing the order of a list. not strictly a sorting function....
Definition sorts.h:362
basis::array< type > merge_sort(const basis::array< type > &v, bool reverse=false)
Definition sorts.h:131
void heap_sort(type v[], int n, bool reverse=false)
Definition sorts.h:283
int partition(type a[], int start, int end, bool reverse)
Definition sorts.h:312
void quick_sort(type v[], int n, bool reverse=false)
Definition sorts.h:353
void inner_quick_sort(type v[], int start, int end, bool reverse)
the recursive version of quick sort that does the work for our convenience method.
Definition sorts.h:336
void shell_sort(type v[], int n, bool reverse=false)
shell sort algorithm.
Definition sorts.h:55
basis::array< type > merge(basis::array< type > &first, basis::array< type > &second, bool reverse)
Definition sorts.h:99
basis::astring dump_list(type v[], int size)
dumps the contents of the list out, assuming that the type can be turned into an int.
Definition sorts.h:38
#define randomizer()