Sort.inl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /* Copyright The kNet Project.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License. */
  11. #pragma once
  12. /** @file Sort.inl
  13. @brief Implementations of template functions for sorting algorithms. */
  14. #ifdef __GNUC__
  15. /// If a variable or a function definition is labelled with this directive, the compiler should not emit a warning even if it is unused
  16. /// in the code.
  17. #define DONT_WARN_UNUSED __attribute__((unused))
  18. #else
  19. #define DONT_WARN_UNUSED
  20. #endif
  21. #include <utility>
  22. namespace kNet
  23. {
  24. namespace sort
  25. {
  26. template<typename T, typename CmpFunc>
  27. void SelectionSort(T *list, int numItems, CmpFunc &cmp)
  28. {
  29. assert(numItems >= 0);
  30. assert(list);
  31. for(int i = 0; i < numItems-1; i++)
  32. {
  33. // find the smallest element of subarray A[i+1] -> A[numItems-1]
  34. T *smallest = &list[i+1];
  35. for(int j = i+2; j < numItems; j++)
  36. if (cmp(list[j], *smallest) < 0)
  37. smallest = &list[j];
  38. // exchange the smallest & current element
  39. if (cmp(*smallest, list[i]) < 0)
  40. std::swap(list[i], *smallest);
  41. }
  42. }
  43. template<typename T, typename CmpFunc>
  44. void PartialSelectionSort(T *list, int numItems, int numItemsToSort, CmpFunc &cmp)
  45. {
  46. assert(numItems >= 0);
  47. assert(numItemsToSort >= 0);
  48. assert(list);
  49. if (numItemsToSort > numItems-1)
  50. numItemsToSort = numItems-1;
  51. for(int i = 0; i < numItemsToSort; i++)
  52. {
  53. // find the smallest element of subarray A[i+1] -> A[numItems-1]
  54. T *smallest = &list[i+1];
  55. for(int j = i+2; j < numItems; j++)
  56. if (cmp(list[j], *smallest) < 0)
  57. smallest = &list[j];
  58. // exchange the smallest & current element
  59. if (cmp(*smallest, list[i]) < 0)
  60. std::swap(list[i], *smallest);
  61. }
  62. }
  63. template<typename T, typename CmpFunc>
  64. void InsertionSort(T *list, int numItems, CmpFunc &cmp)
  65. {
  66. assert(numItems >= 0);
  67. assert(list);
  68. // The subarray [0, j[ is always in sorted order.
  69. for(int j = 1; j < numItems; j++)
  70. {
  71. const T item = list[j];
  72. int i = j-1;
  73. while(i >= 0 && cmp(list[i], item) > 0)
  74. {
  75. list[i+1] = list[i];
  76. i--;
  77. }
  78. list[i+1] = item;
  79. }
  80. }
  81. namespace
  82. {
  83. /// Used by merge sort. This algorithm merges two subarrays into a larger, sorted array.
  84. template<typename T, typename CmpFunc>
  85. void MergeSubSet(T *list, int first, int split, int last, T *tempArray, CmpFunc &cmp)
  86. {
  87. assert(first >= 0);
  88. assert(split >= 0);
  89. assert(last >= 0);
  90. assert(list);
  91. assert(tempArray);
  92. if (first > split || split >= last)
  93. return;
  94. // create two subarrays:
  95. // left: array[first] -> array[split] size: split-first+1
  96. // right: array[split+1] -> array[last] size: last-split
  97. // the item array[split] goes to left subarray
  98. // create left
  99. int sLeft = split-first+1;
  100. T *left = tempArray;
  101. for(int i = 0; i < sLeft; i++)
  102. left[i] = list[first+i];
  103. // create right
  104. int sRight = last-split;
  105. T *right = &tempArray[sLeft];
  106. for(int i = 0; i < sRight; i++)
  107. right[i] = list[split+1+i];
  108. // left & right are assumed to be sorted subarrays,
  109. // use the original array as destination
  110. int iLeft = 0;
  111. int iRight = 0;
  112. int idx = first;
  113. for(; idx <= last && iLeft < sLeft && iRight < sRight; idx++)
  114. if (cmp(left[iLeft], right[iRight]) < 0)
  115. list[idx] = left[iLeft++];
  116. else
  117. list[idx] = right[iRight++];
  118. // the for-loop ended, copy the remaining pile to array
  119. for(; iLeft < sLeft; iLeft++)
  120. list[idx++] = left[iLeft];
  121. for(; iRight < sRight; iRight++)
  122. list[idx++] = right[iRight];
  123. }
  124. // Used by merge sort
  125. template<typename T, typename CmpFunc>
  126. void MergeSort(T *list, int first, int last, T *temp, CmpFunc &cmp)
  127. {
  128. assert(first >= 0);
  129. assert(last >= 0);
  130. assert(list);
  131. assert(temp);
  132. if (first >= last)
  133. return;
  134. int half = (first+last)/2;
  135. MergeSort(list, first, half, temp, cmp);
  136. MergeSort(list, half+1, last, temp, cmp);
  137. MergeSubSet(list, first, half, last, temp, cmp);
  138. }
  139. }
  140. template<typename T, typename CmpFunc>
  141. void MergeSort(T *list, int numItems, CmpFunc &cmp)
  142. {
  143. assert(numItems >= 0);
  144. assert(list);
  145. T *tempArray = new T[numItems];
  146. MergeSort(list, 0, numItems-1, tempArray, cmp);
  147. delete[] tempArray;
  148. }
  149. namespace
  150. {
  151. template<typename T, typename CmpFunc>
  152. void GapInsertSort(T *list, int gapSize, int numItems, CmpFunc &cmp)
  153. {
  154. assert(numItems >= 0);
  155. assert(list);
  156. assert(gapSize >= 1);
  157. for(int j = gapSize; j < numItems; j++)
  158. {
  159. const T item = list[j];
  160. int i = j - gapSize;
  161. while(i >= 0 && cmp(list[i], item) > 0)
  162. {
  163. list[i + gapSize] = list[i];
  164. i -= gapSize;
  165. }
  166. list[i + gapSize] = item;
  167. }
  168. }
  169. } // ~unnamed namespace
  170. template<typename T, typename CmpFunc>
  171. void ShellSort(T *list, int numItems, CmpFunc &cmp)
  172. {
  173. assert(numItems >= 0);
  174. assert(list);
  175. // The increments to use for gap insertion sort.
  176. // http://www.research.att.com/~njas/sequences/A102549
  177. static const int gaps[] = { 1, 4, 10, 23, 57, 132, 301, 701 };
  178. for(int i = sizeof(gaps)/sizeof(gaps[0]) - 1; i >= 0; --i)
  179. GapInsertSort(list, gaps[i], numItems, cmp);
  180. }
  181. /** On the development computer overflows the stack if numItems is larger than ~57000
  182. and the list is already sorted. */
  183. template<typename T, typename CmpFunc>
  184. void QuickSort(T *list, int numItems, CmpFunc &cmp)
  185. {
  186. assert(numItems >= 0);
  187. assert(list);
  188. if (numItems <= 1)
  189. return;
  190. // Select the middle item as pivot. (In a nearly sorted list, this is as near of the
  191. // median value as we can get) The pivot is stored at the back of the array.
  192. std::swap(list[numItems-1], list[numItems/2]);
  193. const T &pivotValue = list[numItems-1];
  194. // Do the actual pivotizing.
  195. int rEnd = 0;
  196. for(int i = 0; i < numItems-1; i++)
  197. if (cmp(list[i], pivotValue) < 0)
  198. std::swap(list[rEnd++], list[i]);
  199. // Put the pivot value to the center of the array
  200. std::swap(list[rEnd], list[numItems-1]);
  201. // sort left & right
  202. if (rEnd > 1) // if left side has more than one item, sort it.
  203. QuickSort(list, rEnd, cmp);
  204. if (numItems-rEnd>2) // if right side has more than one item, sort it.
  205. QuickSort(&list[rEnd+1], numItems-rEnd-1, cmp);
  206. }
  207. template<typename T, typename CmpFunc>
  208. void BubbleSort(T *list, int numItems, CmpFunc &cmp)
  209. {
  210. assert(numItems >= 0);
  211. assert(list);
  212. int inOrderIndex = numItems; // Denotes the subarray that is already sorted, i.e. [inOrderIndex, numItems[.
  213. while(inOrderIndex > 0)
  214. {
  215. int largestSwapped = 0; // Track the largest index that was changed. To early-out the outer loop.
  216. for(int j = 1; j < inOrderIndex; ++j)
  217. if (cmp(list[j-1], list[j]) > 0)
  218. {
  219. std::swap(list[j-1], list[j]);
  220. largestSwapped = j;
  221. }
  222. inOrderIndex = largestSwapped;
  223. }
  224. }
  225. template<typename T, typename CmpFunc>
  226. void CombSort(T *list, int numItems, CmpFunc &cmp)
  227. {
  228. assert(numItems >= 0);
  229. assert(list);
  230. int gap = numItems;
  231. bool bSwitches = false;
  232. do
  233. {
  234. bSwitches = false;
  235. // Reduce the gap by dividing by 1/(1-1/e^phi)
  236. gap = (int)(gap / 1.24733095f);
  237. if (gap == 10 || gap == 9) // gap size 11 is superior to 10 or 9, use that instead.
  238. gap = 11;
  239. else if (gap < 1) // the last iteration needs to be with gap=1 (bubblesort)
  240. gap = 1;
  241. for(int i = 0; i < numItems-gap; i++)
  242. if (cmp(list[i+gap], list[i]) < 0)
  243. {
  244. std::swap(list[i+gap], list[i]);
  245. bSwitches = true;
  246. }
  247. } while(gap > 1 || bSwitches);
  248. }
  249. /** Works by alternating the bubble directions in bubble sort. */
  250. template<typename T, typename CmpFunc>
  251. void CocktailSort(T *list, int numItems, CmpFunc &cmp)
  252. {
  253. assert(numItems >= 0);
  254. assert(list);
  255. int bottomSorted = 0; // Number of items in the low end that are already sorted. (Index of first unsorted)
  256. int topSorted = numItems; // Index of the first sorted item in the high end.
  257. while(bottomSorted+1 < topSorted) // The outer loop, condition for early-outing
  258. {
  259. // Tracks the index that was last modified, in order to prune a few elements in the bubbling process.
  260. int lastSwapped = bottomSorted;
  261. for(int i = bottomSorted+1; i < topSorted; ++i) // Rising pass
  262. if (cmp(list[i-1], list[i]) > 0)
  263. {
  264. std::swap(list[i-1], list[i]);
  265. lastSwapped = i;
  266. }
  267. topSorted = lastSwapped;
  268. // We reuse the value that was left in lastSwapped here to remember the last index that was swapped.
  269. // (Allows early-out)
  270. for(int i = topSorted-1; i > bottomSorted; --i) // Falling pass
  271. if (cmp(list[i-1], list[i]) > 0)
  272. {
  273. std::swap(list[i-1], list[i]);
  274. lastSwapped = i;
  275. }
  276. bottomSorted = lastSwapped;
  277. }
  278. }
  279. namespace
  280. {
  281. /// Gives the index of the parent of the element at index i, or 0 if i==0 (i is the root)
  282. inline int DONT_WARN_UNUSED HeapParent(int i) { return (i+1)/2-1; }
  283. /// Gives the left child of the element at index i. Note that this will address out-of-bounds if there is no child.
  284. inline int DONT_WARN_UNUSED HeapLeftChild(int i) { return i*2+1; }
  285. /// Gives the right child of the element at index i. Note that this will address out-of-bounds if there is no child.
  286. inline int DONT_WARN_UNUSED HeapRightChild(int i) { return i*2+2; }
  287. /** MaxHeapifies one node of the heap at index i and recursively calls itself to MaxHeapify the child nodes,
  288. so that all child nodes also satisfy the MaxHeap property.
  289. @param list An array that represents the (binary) heap.
  290. @param heapSize The number of elements in the heap.
  291. @param i The index of the element to start MaxHeapifying at.
  292. @param cmp A function that compares the priorities of two elements. See above.
  293. @return True if changes (swaps) needed to be made to the heap at the given position, false otherwise. */
  294. template<typename T, typename PriorityCmp>
  295. bool MaxHeapify(T *heap, int heapSize, int i, PriorityCmp &cmp)
  296. {
  297. assert(heapSize >= 0);
  298. assert(i >= 0);
  299. assert(heap);
  300. // Get the indices to both children. Note that these might point to >= heapSize if a child is not present.
  301. const int l = HeapLeftChild(i);
  302. const int r = HeapRightChild(i);
  303. // Determine the largest node
  304. int largest = i;
  305. if (l < heapSize && cmp(heap[l], heap[i]) > 0)
  306. largest = l;
  307. if (r < heapSize && cmp(heap[r], heap[largest]) > 0)
  308. largest = r;
  309. // If i is not the largest node, switch and MaxHeapify the child node.
  310. if (largest != i)
  311. {
  312. std::swap(heap[largest], heap[i]);
  313. MaxHeapify(heap, heapSize, largest, cmp);
  314. return true; // Changes were made to heap.
  315. }
  316. return false; // No changes were made to heap.
  317. }
  318. /** Takes an array of items and builds it into a MaxHeap, i.e. swaps elements around so that the ordering
  319. satisfies the MaxHeap property. Building a MaxHeap from an array that is in random order takes O(n) steps.
  320. (If we do it bottom-up by pushing elements upwards like here. Takes a lot more if we would go top-down).
  321. @param list An array that represents a (binary) heap.
  322. @param heapSize The number of items in the array.
  323. @param cmp The comparison function to use for the elements. */
  324. template<typename T, typename PriorityCmp>
  325. void BuildMaxHeap(T *list, int heapSize, PriorityCmp &cmp)
  326. {
  327. assert(heapSize >= 0);
  328. assert(list);
  329. // MaxHeapify the whole heap by starting from the lowest non-leaf node and go our way up.
  330. for(int i = (heapSize-1)/2; i >= 0; i--)
  331. MaxHeapify(list, heapSize, i, cmp);
  332. }
  333. } // ~unnamed namespace
  334. template<typename T, typename CmpFunc>
  335. void HeapSort(T *list, int numItems, CmpFunc &cmp)
  336. {
  337. assert(numItems >= 0);
  338. assert(list);
  339. BuildMaxHeap(list, numItems, cmp);
  340. // At every iteration, we have the largest item in list[0], switch it to the back of the
  341. // list and remove the swapped item from the heap. Then re-MaxHeapify and repeat.
  342. for(int i = numItems-1; i > 0; i--)
  343. {
  344. std::swap(list[0], list[i]);
  345. MaxHeapify(list, i, 0, cmp);
  346. }
  347. }
  348. template<typename T, typename CmpFunc>
  349. void IntroSort(T *list, int numItems, int nMaxRecursionLevels, CmpFunc &cmp)
  350. {
  351. assert(numItems >= 0);
  352. assert(nMaxRecursionLevels >= 0);
  353. assert(list);
  354. if (numItems <= 1)
  355. return;
  356. // Select the middle item as pivot. (In a nearly sorted list, this is as near of the
  357. // median value as we can get)
  358. std::swap(list[numItems-1], list[numItems/2]);
  359. const T pivotValue = list[numItems-1];
  360. int rEnd = -1;
  361. for(int i = 0; i < numItems-1; i++)
  362. if (cmp(list[i], pivotValue) <= 0)
  363. {
  364. ++rEnd;
  365. std::swap(list[rEnd], list[i]);
  366. }
  367. // put the pivot value to the center of the array
  368. std::swap(list[rEnd+1], list[numItems-1]);
  369. if (nMaxRecursionLevels > 0)
  370. {
  371. // sort left & right
  372. if (rEnd > 0) // if left side has more than one item, sort it.
  373. IntroSort(list, rEnd+1,nMaxRecursionLevels-1, cmp);
  374. if (numItems-rEnd>3) // if right side has more than one item, sort it.
  375. IntroSort(&list[rEnd+2], numItems - rEnd-2,nMaxRecursionLevels-1, cmp);
  376. }
  377. else
  378. {
  379. // sort left & right
  380. if (rEnd > 0) // if left side has more than one item, sort it.
  381. HeapSort(list, rEnd+1, cmp);
  382. if (numItems-rEnd>3) // if right side has more than one item, sort it.
  383. HeapSort(&list[rEnd+2], numItems - rEnd-2, cmp);
  384. }
  385. }
  386. template<typename T, typename CmpFunc>
  387. bool IsSorted(T *list, int numItems, CmpFunc &cmp)
  388. {
  389. for(size_t i = 0; i+1 < numItems; ++i)
  390. if (cmp(list[i], list[i+1]) > 0)
  391. return false;
  392. return true;
  393. }
  394. } // ~sort
  395. } // ~kNet