1 #ifndef ASSORTED_SORTS_GROUP
2 #define ASSORTED_SORTS_GROUP
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.
19 namespace algorithms {
22 * general considerations:
24 * + Generic objects to be sorted must support comparison operators.
26 * + If the "reverse" flag is true, the arrays will be sorted in reverse order.
27 * Reverse order here means "descending", such that array element i is always greater than or equal to array element i+1.
28 * Normal order is "ascending", such that element i is always less than or equal to array element i+1.
32 //! dumps the contents of the list out, assuming that the type can be turned into an int.
34 basis::astring dump_list(type v[], int size)
37 for (int i = 0; i < size; i++) {
38 ret += basis::a_sprintf("%d ", (int)v[i]);
43 //! shell sort algorithm.
45 * Sorts a C array of the "type" with "n" elements.
46 * Operates on the original array.
47 * Performs within O(n^2) time (depending on the gap size used).
48 * Algorithm is based on Kernighan and Ritchie's "The C Programming Language".
51 void shell_sort(type v[], int n, bool reverse = false)
55 /* the gap sizes decrease quadratically(?). they partition the array of
56 * items that need to be sorted into first two groups, then four, then
57 * eight, etc. the inner loop iterates across each gap's worth of the array.
59 for (gap = n / 2; gap > 0; gap /= 2) {
60 // the i indexed loop is the base for where the comparisons are made in
61 // the j indexed loop. it makes sure that each item past the edge of
62 // the gap sized partition gets considered.
63 for (i = gap; i < n; i++) {
64 // the j indexed loop looks at the values in our current gap and ensures
65 // that they are in sorted order.
68 for (j = i - gap; j >= 0 && v[j] > v[j + gap]; j = j - gap) {
69 // swap the elements that are disordered.
76 for (j = i - gap; j >= 0 && v[j] < v[j + gap]; j = j - gap) {
77 // swap the elements that are disordered.
92 * merges two sorted arrays into a single sorted array.
95 basis::array<type> merge(basis::array<type> &first, basis::array<type> &second, bool reverse)
97 basis::array<type> to_return;
98 // operate until we've consumed both of the arrays.
99 while ((first.length() > 0) || (second.length() > 0)) {
100 if (first.length() <= 0) {
101 // nothing left in first, so use the second.
102 to_return += second[0];
104 } else if (second.length() <= 0) {
105 to_return += first[0];
107 } else if ((!reverse && (first[0] <= second[0])) || (reverse && (first[0] >= second[0]))) {
108 // the first list has a better value to add next.
109 to_return += first[0];
112 // the second list has a better value to add next.
113 to_return += second[0];
123 * operates in O(n log(n)) time.
124 * returns a new array with sorted data.
127 basis::array<type> merge_sort(const basis::array<type> &v, bool reverse = false)
129 if (v.length() <= 1) {
130 return basis::array<type>(v);
132 int midway = v.length() / 2;
133 basis::array<type> firstPart = merge_sort(v.subarray(0, midway - 1), reverse);
134 basis::array<type> secondPart = merge_sort(v.subarray(midway, v.length() - 1), reverse);
135 return merge(firstPart, secondPart, reverse);
141 * a heap is a structure that can quickly return the highest (or lowest) value,
142 * depending on how the priority of the item is defined.
143 * a "normal" heap keeps the highest element available first; a reverse sorted heap
144 * keeps the lowest element available first.
145 * restructuring the heap is fast, and is O(n log(n)).
146 * the implicit structure is a binary tree
147 * represented in a flat array, where the children of a node at position n are
148 * in positions n * 2 + 1 and n * 2 + 2 (zero based).
150 //hmmm: move this class out to basis?.
155 heap(type to_sort[], int n, bool reverse)
159 _heapspace = to_sort;
163 //! swaps the values in the heap stored at positions a and b.
164 void swap_values(int a, int b)
166 type temp = _heapspace[a];
167 _heapspace[a] = _heapspace[b];
168 _heapspace[b] = temp;
171 //! get the index of the parent of the node at i.
172 /*! this will not return the parent index of the root, since there is no parent. */
173 int parent_index(int i)
175 return i / 2; // rely on integer division to shave off remainder.
178 //! returns the left child of node at position i.
179 int left_child(int i)
184 //! returns the right child of node at position i.
185 int right_child(int i)
190 //! re-sorts the heapspace to maintain the heap ordering.
193 int start = parent_index(_total - 1);
194 // iterate from the back of the array towards the front, so depth-first.
196 // sift down the node at the index 'start' such that all nodes below it are heapified.
197 sift_down(start, _total - 1);
198 start--; // move the start upwards towards the root.
202 void sift_down(int start, int end)
206 // while the current root still has a kid...
207 while (left_child(root) <= end) {
208 int child = left_child(root);
209 // figure out which child to swap with.
211 // check if the root should be swapped with this kid.
212 if ((!_reverse && (_heapspace[swap] > _heapspace[child]))
213 || (_reverse && (_heapspace[swap] < _heapspace[child])))
217 // check if the other child should be swapped with the root or left kid.
218 if ((child + 1 <= end)
219 && ((!_reverse && (_heapspace[swap] > _heapspace[child + 1]))
220 || (_reverse && (_heapspace[swap] < _heapspace[child + 1]))))
225 // the root has the largest (or smallest) element, so we're done.
228 swap_values(root, swap);
230 // repeat to continue sifting down the child now.
235 //! re-sorts the heapspace to maintain the heap ordering. this uses sift_up.
238 int end = 1; // start at first child.
240 while (end < _total) {
241 // sift down the node at the index 'start' such that all nodes below it are heapified.
246 //! start is how far up in the heap to sort. end is the node to sift.
247 void sift_up(int start, int end)
250 // loop until we hit the starting node, where we're done.
251 while (child > start) {
252 int parent = parent_index(child);
253 if ((!_reverse && (_heapspace[parent] < _heapspace[child]))
254 || (_reverse && (_heapspace[parent] > _heapspace[child])))
256 swap_values(parent, child);
258 // continue sifting at the parent now.
267 bool _reverse = false; // is the sorting in reverse?
269 int *_heapspace = NULL_POINTER;
275 * operates in O(n log(n)).
276 * sorts the original array.
279 void heap_sort(type v[], int n, bool reverse = false)
281 // reverse the sense of "reverse", since our algorithm expects a normal heap (with largest on top).
282 heap<type> hap(v, n, !reverse);
286 // 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.
287 hap.swap_values(end, 0);
288 // reduce the heap size by 1.
290 // that swap ruined the heap property, so re-heapify.
291 hap.sift_down(0, end);
297 //! swaps the values in the array stored at positions a and b.
299 void swap_values(type array[], int a, int b)
301 type temp = array[a];
306 // hoare's partition implementation.
308 int partition(type a[], int start, int end, bool reverse)
310 // printf("before partition: %s\n", dump_list(a + start, end - start + 1).s());
311 int pivot = a[start];
317 } while ((!reverse && (a[i] < pivot)) || (reverse && (a[i] > pivot)));
320 } while ((!reverse && (a[j] > pivot)) || (reverse && (a[j] < pivot)));
323 // printf("after partition: %s\n", dump_list(a + start, end - start + 1).s());
326 swap_values(a, i, j);
330 //! the recursive version of quick sort that does the work for our convenience method.
332 void inner_quick_sort(type v[], int start, int end, bool reverse)
335 // figure out where to pivot, and sort both halves around the pivot index.
336 int pivot = partition(v, start, end, reverse);
337 inner_quick_sort(v, start, pivot, reverse);
338 inner_quick_sort(v, pivot + 1, end, reverse);
345 * operates in O(n log(n)) time on average, worst case O(n^2).
346 * sorts the original array.
349 void quick_sort(type v[], int n, bool reverse = false)
351 inner_quick_sort(v, 0, n - 1, reverse);
356 #endif // outer guard.