Sort.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #ifndef __SORT_H__
  21. #define __SORT_H__
  22. /*
  23. ================================================================================================
  24. Contains the generic templated sort algorithms for quick-sort, heap-sort and insertion-sort.
  25. The sort algorithms do not use class operators or overloaded functions to compare
  26. objects because it is often desireable to sort the same objects in different ways
  27. based on different keys (not just ascending and descending but sometimes based on
  28. name and other times based on say priority). So instead, for each different sort a
  29. separate class is implemented with a Compare() function.
  30. This class is derived from one of the classes that implements a sort algorithm.
  31. The Compare() member function does not only define how objects are sorted, the class
  32. can also store additional data that can be used by the Compare() function. This, for
  33. instance, allows a list of indices to be sorted where the indices point to objects
  34. in an array. The base pointer of the array with objects can be stored on the class
  35. that implements the Compare() function such that the Compare() function can use keys
  36. that are stored on the objects.
  37. The Compare() function is not virtual because this would incur significant overhead.
  38. Do NOT make the Compare() function virtual on the derived class!
  39. The sort implementations also explicitely call the Compare() function of the derived
  40. class. This is to avoid various compiler bugs with using overloaded compare functions
  41. and the inability of various compilers to find the right overloaded compare function.
  42. To sort an array, an idList or an idStaticList, a new sort class, typically derived from
  43. idSort_Quick, is implemented as follows:
  44. class idSort_MySort : public idSort_Quick< idMyObject, idSort_MySort > {
  45. public:
  46. int Compare( const idMyObject & a, const idMyObject & b ) const {
  47. if ( a should come before b ) {
  48. return -1; // or any negative integer
  49. } if ( a should come after b ) {
  50. return 1; // or any positive integer
  51. } else {
  52. return 0;
  53. }
  54. }
  55. };
  56. To sort an array:
  57. idMyObject array[100];
  58. idSort_MySort().Sort( array, 100 );
  59. To sort an idList:
  60. idList< idMyObject > list;
  61. list.Sort( idSort_MySort() );
  62. The sort implementations never create temporaries of the template type. Only the
  63. 'SwapValues' template is used to move data around. This 'SwapValues' template can be
  64. specialized to implement fast swapping of data. For instance, when sorting a list with
  65. objects of some string class it is important to implement a specialized 'SwapValues' for
  66. this string class to avoid excessive re-allocation and copying of strings.
  67. ================================================================================================
  68. */
  69. /*
  70. ========================
  71. SwapValues
  72. ========================
  73. */
  74. template< typename _type_ >
  75. ID_INLINE void SwapValues( _type_ & a, _type_ & b ) {
  76. _type_ c = a;
  77. a = b;
  78. b = c;
  79. }
  80. /*
  81. ================================================
  82. idSort is an abstract template class for sorting an array of objects of the specified data type.
  83. The array of objects is sorted such that: Compare( array[i], array[i+1] ) <= 0 for all i
  84. ================================================
  85. */
  86. template< typename _type_ >
  87. class idSort {
  88. public:
  89. virtual ~idSort() {}
  90. virtual void Sort( _type_ * base, unsigned int num ) const = 0;
  91. };
  92. /*
  93. ================================================
  94. idSort_Quick is a sort template that implements the
  95. quick-sort algorithm on an array of objects of the specified data type.
  96. ================================================
  97. */
  98. template< typename _type_, typename _derived_ >
  99. class idSort_Quick : public idSort< _type_ > {
  100. public:
  101. virtual void Sort( _type_ * base, unsigned int num ) const {
  102. if ( num <= 0 ) {
  103. return;
  104. }
  105. const int64 MAX_LEVELS = 128;
  106. int64 lo[MAX_LEVELS], hi[MAX_LEVELS];
  107. // 'lo' is the lower index, 'hi' is the upper index
  108. // of the region of the array that is being sorted.
  109. lo[0] = 0;
  110. hi[0] = num - 1;
  111. for ( int64 level = 0; level >= 0; ) {
  112. int64 i = lo[level];
  113. int64 j = hi[level];
  114. // Only use quick-sort when there are 4 or more elements in this region and we are below MAX_LEVELS.
  115. // Otherwise fall back to an insertion-sort.
  116. if ( ( ( j - i ) >= 4 ) && ( level < ( MAX_LEVELS - 1 ) ) ) {
  117. // Use the center element as the pivot.
  118. // The median of a multi point sample could be used
  119. // but simply taking the center works quite well.
  120. int64 pi = ( i + j ) / 2;
  121. // Move the pivot element to the end of the region.
  122. SwapValues( base[j], base[pi] );
  123. // Get a reference to the pivot element.
  124. _type_ & pivot = base[j--];
  125. // Partition the region.
  126. do {
  127. while( static_cast< const _derived_ * >( this )->Compare( base[i], pivot ) < 0 ) { if ( ++i >= j ) break; }
  128. while( static_cast< const _derived_ * >( this )->Compare( base[j], pivot ) > 0 ) { if ( --j <= i ) break; }
  129. if ( i >= j ) break;
  130. SwapValues( base[i], base[j] );
  131. } while( ++i < --j );
  132. // Without these iterations sorting of arrays with many duplicates may
  133. // become really slow because the partitioning can be very unbalanced.
  134. // However, these iterations are unnecessary if all elements are unique.
  135. while ( static_cast< const _derived_ * >( this )->Compare( base[i], pivot ) <= 0 && i < hi[level] ) { i++; }
  136. while ( static_cast< const _derived_ * >( this )->Compare( base[j], pivot ) >= 0 && lo[level] < j ) { j--; }
  137. // Move the pivot element in place.
  138. SwapValues( pivot, base[i] );
  139. assert( level < MAX_LEVELS - 1 );
  140. lo[level+1] = i;
  141. hi[level+1] = hi[level];
  142. hi[level] = j;
  143. level++;
  144. } else {
  145. // Insertion-sort of the remaining elements.
  146. for( ; i < j; j-- ) {
  147. int64 m = i;
  148. for ( int64 k = i + 1; k <= j; k++ ) {
  149. if ( static_cast< const _derived_ * >( this )->Compare( base[k], base[m] ) > 0 ) {
  150. m = k;
  151. }
  152. }
  153. SwapValues( base[m], base[j] );
  154. }
  155. level--;
  156. }
  157. }
  158. }
  159. };
  160. /*
  161. ================================================
  162. Default quick-sort comparison function that can
  163. be used to sort scalars from small to large.
  164. ================================================
  165. */
  166. template< typename _type_ >
  167. class idSort_QuickDefault : public idSort_Quick< _type_, idSort_QuickDefault< _type_ > > {
  168. public:
  169. int Compare( const _type_ & a, const _type_ & b ) const { return a - b; }
  170. };
  171. /*
  172. ================================================
  173. Specialization for floating point values to avoid an float-to-int
  174. conversion for every comparison.
  175. ================================================
  176. */
  177. template<>
  178. class idSort_QuickDefault< float > : public idSort_Quick< float, idSort_QuickDefault< float > > {
  179. public:
  180. int Compare( const float & a, const float & b ) const {
  181. if ( a < b ) {
  182. return -1;
  183. }
  184. if ( a > b ) {
  185. return 1;
  186. }
  187. return 0;
  188. }
  189. };
  190. /*
  191. ================================================
  192. idSort_Heap is a sort template class that implements the
  193. heap-sort algorithm on an array of objects of the specified data type.
  194. ================================================
  195. */
  196. template< typename _type_, typename _derived_ >
  197. class idSort_Heap : public idSort< _type_ > {
  198. public:
  199. virtual void Sort( _type_ * base, unsigned int num ) const {
  200. // get all elements in heap order
  201. #if 1
  202. // O( n )
  203. for ( unsigned int i = num / 2; i > 0; i-- ) {
  204. // sift down
  205. unsigned int parent = i - 1;
  206. for ( unsigned int child = parent * 2 + 1; child < num; child = parent * 2 + 1 ) {
  207. if ( child + 1 < num && static_cast< const _derived_ * >( this )->Compare( base[child + 1], base[child] ) > 0 ) {
  208. child++;
  209. }
  210. if ( static_cast< const _derived_ * >( this )->Compare( base[child], base[parent] ) <= 0 ) {
  211. break;
  212. }
  213. SwapValues( base[parent], base[child] );
  214. parent = child;
  215. }
  216. }
  217. #else
  218. // O(n log n)
  219. for ( unsigned int i = 1; i < num; i++ ) {
  220. // sift up
  221. for ( unsigned int child = i; child > 0; ) {
  222. unsigned int parent = ( child - 1 ) / 2;
  223. if ( static_cast< const _derived_ * >( this )->Compare( base[parent], base[child] ) > 0 ) {
  224. break;
  225. }
  226. SwapValues( base[child], base[parent] );
  227. child = parent;
  228. }
  229. }
  230. #endif
  231. // get sorted elements while maintaining heap order
  232. for ( unsigned int i = num - 1; i > 0; i-- ) {
  233. SwapValues( base[0], base[i] );
  234. // sift down
  235. unsigned int parent = 0;
  236. for ( unsigned int child = parent * 2 + 1; child < i; child = parent * 2 + 1 ) {
  237. if ( child + 1 < i && static_cast< const _derived_ * >( this )->Compare( base[child + 1], base[child] ) > 0 ) {
  238. child++;
  239. }
  240. if ( static_cast< const _derived_ * >( this )->Compare( base[child], base[parent] ) <= 0 ) {
  241. break;
  242. }
  243. SwapValues( base[parent], base[child] );
  244. parent = child;
  245. }
  246. }
  247. }
  248. };
  249. /*
  250. ================================================
  251. Default heap-sort comparison function that can
  252. be used to sort scalars from small to large.
  253. ================================================
  254. */
  255. template< typename _type_ >
  256. class idSort_HeapDefault : public idSort_Heap< _type_, idSort_HeapDefault< _type_ > > {
  257. public:
  258. int Compare( const _type_ & a, const _type_ & b ) const { return a - b; }
  259. };
  260. /*
  261. ================================================
  262. idSort_Insertion is a sort template class that implements the
  263. insertion-sort algorithm on an array of objects of the specified data type.
  264. ================================================
  265. */
  266. template< typename _type_, typename _derived_ >
  267. class idSort_Insertion : public idSort< _type_ > {
  268. public:
  269. virtual void Sort( _type_ * base, unsigned int num ) const {
  270. _type_ * lo = base;
  271. _type_ * hi = base + ( num - 1 );
  272. while( hi > lo ) {
  273. _type_ * max = lo;
  274. for ( _type_ * p = lo + 1; p <= hi; p++ ) {
  275. if ( static_cast< const _derived_ * >( this )->Compare( (*p), (*max) ) > 0 ) {
  276. max = p;
  277. }
  278. }
  279. SwapValues( *max, *hi );
  280. hi--;
  281. }
  282. }
  283. };
  284. /*
  285. ================================================
  286. Default insertion-sort comparison function that can
  287. be used to sort scalars from small to large.
  288. ================================================
  289. */
  290. template< typename _type_ >
  291. class idSort_InsertionDefault : public idSort_Insertion< _type_, idSort_InsertionDefault< _type_ > > {
  292. public:
  293. int Compare( const _type_ & a, const _type_ & b ) const { return a - b; }
  294. };
  295. #endif // !__SORT_H__