1 #ifndef GIM_RADIXSORT_H_INCLUDED
2 #define GIM_RADIXSORT_H_INCLUDED
3 /*! \file gim_radixsort.h
4 \author Francisco Leon Najera.
5 Based on the work of Michael Herf : "fast floating-point radix sort"
6 Avaliable on http://www.stereopsis.com/radix.html
7 */
8 /*
9 -----------------------------------------------------------------------------
10 This source file is part of GIMPACT Library.
11
12 For the latest info, see http://gimpact.sourceforge.net/
13
14 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
15 email: projectileman@yahoo.com
16
17 This library is free software; you can redistribute it and/or
18 modify it under the terms of EITHER:
19 (1) The GNU Lesser General Public License as published by the Free
20 Software Foundation; either version 2.1 of the License, or (at
21 your option) any later version. The text of the GNU Lesser
22 General Public License is included with this library in the
23 file GIMPACT-LICENSE-LGPL.TXT.
24 (2) The BSD-style license that is included with this library in
25 the file GIMPACT-LICENSE-BSD.TXT.
26 (3) The zlib/libpng license that is included with this library in
27 the file GIMPACT-LICENSE-ZLIB.TXT.
28
29 This library is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
32 GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
33
34 -----------------------------------------------------------------------------
35 */
36
37 #include "gim_memory.h"
38
39 ///Macros for sorting.
40 //! Prototype for comparators
41 class less_comparator
42 {
43 public:
44
45 template<class T,class Z>
operator()46 inline int operator() ( const T& a, const Z& b )
47 {
48 return ( a<b?-1:(a>b?1:0));
49 }
50 };
51
52 //! Prototype for comparators
53 class integer_comparator
54 {
55 public:
56
57 template<class T>
operator()58 inline int operator() ( const T& a, const T& b )
59 {
60 return (int)(a-b);
61 }
62 };
63
64 //!Prototype for getting the integer representation of an object
65 class uint_key_func
66 {
67 public:
68 template<class T>
operator()69 inline GUINT operator()( const T& a)
70 {
71 return (GUINT)a;
72 }
73 };
74
75
76 //!Prototype for copying elements
77 class copy_elements_func
78 {
79 public:
80 template<class T>
operator()81 inline void operator()(T& a,T& b)
82 {
83 a = b;
84 }
85 };
86
87 //!Prototype for copying elements
88 class memcopy_elements_func
89 {
90 public:
91 template<class T>
operator()92 inline void operator()(T& a,T& b)
93 {
94 gim_simd_memcpy(&a,&b,sizeof(T));
95 }
96 };
97
98
99 //! @{
100 struct GIM_RSORT_TOKEN
101 {
102 GUINT m_key;
103 GUINT m_value;
GIM_RSORT_TOKENGIM_RSORT_TOKEN104 GIM_RSORT_TOKEN()
105 {
106 }
GIM_RSORT_TOKENGIM_RSORT_TOKEN107 GIM_RSORT_TOKEN(const GIM_RSORT_TOKEN& rtoken)
108 {
109 m_key = rtoken.m_key;
110 m_value = rtoken.m_value;
111 }
112
113 inline bool operator <(const GIM_RSORT_TOKEN& other) const
114 {
115 return (m_key < other.m_key);
116 }
117
118 inline bool operator >(const GIM_RSORT_TOKEN& other) const
119 {
120 return (m_key > other.m_key);
121 }
122 };
123
124 //! Prototype for comparators
125 class GIM_RSORT_TOKEN_COMPARATOR
126 {
127 public:
128
operator()129 inline int operator()( const GIM_RSORT_TOKEN& a, const GIM_RSORT_TOKEN& b )
130 {
131 return (int)((a.m_key) - (b.m_key));
132 }
133 };
134
135
136
137 #define kHist 2048
138 // ---- utils for accessing 11-bit quantities
139 #define D11_0(x) (x & 0x7FF)
140 #define D11_1(x) (x >> 11 & 0x7FF)
141 #define D11_2(x) (x >> 22 )
142
143
144
145 ///Radix sort for unsigned integer keys
gim_radix_sort_rtokens(GIM_RSORT_TOKEN * array,GIM_RSORT_TOKEN * sorted,GUINT element_count)146 inline void gim_radix_sort_rtokens(
147 GIM_RSORT_TOKEN * array,
148 GIM_RSORT_TOKEN * sorted, GUINT element_count)
149 {
150 GUINT i;
151 GUINT b0[kHist * 3];
152 GUINT *b1 = b0 + kHist;
153 GUINT *b2 = b1 + kHist;
154 for (i = 0; i < kHist * 3; ++i)
155 {
156 b0[i] = 0;
157 }
158 GUINT fi;
159 GUINT pos;
160 for (i = 0; i < element_count; ++i)
161 {
162 fi = array[i].m_key;
163 b0[D11_0(fi)] ++;
164 b1[D11_1(fi)] ++;
165 b2[D11_2(fi)] ++;
166 }
167 {
168 GUINT sum0 = 0, sum1 = 0, sum2 = 0;
169 GUINT tsum;
170 for (i = 0; i < kHist; ++i)
171 {
172 tsum = b0[i] + sum0;
173 b0[i] = sum0 - 1;
174 sum0 = tsum;
175 tsum = b1[i] + sum1;
176 b1[i] = sum1 - 1;
177 sum1 = tsum;
178 tsum = b2[i] + sum2;
179 b2[i] = sum2 - 1;
180 sum2 = tsum;
181 }
182 }
183 for (i = 0; i < element_count; ++i)
184 {
185 fi = array[i].m_key;
186 pos = D11_0(fi);
187 pos = ++b0[pos];
188 sorted[pos].m_key = array[i].m_key;
189 sorted[pos].m_value = array[i].m_value;
190 }
191 for (i = 0; i < element_count; ++i)
192 {
193 fi = sorted[i].m_key;
194 pos = D11_1(fi);
195 pos = ++b1[pos];
196 array[pos].m_key = sorted[i].m_key;
197 array[pos].m_value = sorted[i].m_value;
198 }
199 for (i = 0; i < element_count; ++i)
200 {
201 fi = array[i].m_key;
202 pos = D11_2(fi);
203 pos = ++b2[pos];
204 sorted[pos].m_key = array[i].m_key;
205 sorted[pos].m_value = array[i].m_value;
206 }
207 }
208
209
210
211
212 /// Get the sorted tokens from an array. For generic use. Tokens are IRR_RSORT_TOKEN
213 /*!
214 *\param array Array of elements to sort
215 *\param sorted_tokens Tokens of sorted elements
216 *\param element_count element count
217 *\param uintkey_macro Functor which retrieves the integer representation of an array element
218 */
219 template<typename T, class GETKEY_CLASS>
gim_radix_sort_array_tokens(T * array,GIM_RSORT_TOKEN * sorted_tokens,GUINT element_count,GETKEY_CLASS uintkey_macro)220 void gim_radix_sort_array_tokens(
221 T* array ,
222 GIM_RSORT_TOKEN * sorted_tokens,
223 GUINT element_count,GETKEY_CLASS uintkey_macro)
224 {
225 GIM_RSORT_TOKEN * _unsorted = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN)*element_count);
226 for (GUINT _i=0;_i<element_count;++_i)
227 {
228 _unsorted[_i].m_key = uintkey_macro(array[_i]);
229 _unsorted[_i].m_value = _i;
230 }
231 gim_radix_sort_rtokens(_unsorted,sorted_tokens,element_count);
232 gim_free(_unsorted);
233 gim_free(_unsorted);
234 }
235
236 /// Sorts array in place. For generic use
237 /*!
238 \param type Type of the array
239 \param array
240 \param element_count
241 \param get_uintkey_macro Macro for extract the Integer value of the element. Similar to SIMPLE_GET_UINTKEY
242 \param copy_elements_macro Macro for copy elements, similar to SIMPLE_COPY_ELEMENTS
243 */
244 template<typename T, class GETKEY_CLASS, class COPY_CLASS>
gim_radix_sort(T * array,GUINT element_count,GETKEY_CLASS get_uintkey_macro,COPY_CLASS copy_elements_macro)245 void gim_radix_sort(
246 T * array, GUINT element_count,
247 GETKEY_CLASS get_uintkey_macro, COPY_CLASS copy_elements_macro)
248 {
249 GIM_RSORT_TOKEN * _sorted = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN)*element_count);
250 gim_radix_sort_array_tokens(array,_sorted,element_count,get_uintkey_macro);
251 T * _original_array = (T *) gim_alloc(sizeof(T)*element_count);
252 gim_simd_memcpy(_original_array,array,sizeof(T)*element_count);
253 for (GUINT _i=0;_i<element_count;++_i)
254 {
255 copy_elements_macro(array[_i],_original_array[_sorted[_i].m_value]);
256 }
257 gim_free(_original_array);
258 gim_free(_sorted);
259 }
260
261 //! Failsafe Iterative binary search,
262 /*!
263 If the element is not found, it returns the nearest upper element position, may be the further position after the last element.
264 \param _array
265 \param _start_i the beginning of the array
266 \param _end_i the ending index of the array
267 \param _search_key Value to find
268 \param _comp_macro macro for comparing elements
269 \param _found If true the value has found. Boolean
270 \param _result_index the index of the found element, or if not found then it will get the index of the closest bigger value
271 */
272 template<class T, typename KEYCLASS, typename COMP_CLASS>
gim_binary_search_ex(const T * _array,GUINT _start_i,GUINT _end_i,GUINT & _result_index,const KEYCLASS & _search_key,COMP_CLASS _comp_macro)273 bool gim_binary_search_ex(
274 const T* _array, GUINT _start_i,
275 GUINT _end_i,GUINT & _result_index,
276 const KEYCLASS & _search_key,
277 COMP_CLASS _comp_macro)
278 {
279 GUINT _k;
280 int _comp_result;
281 GUINT _i = _start_i;
282 GUINT _j = _end_i+1;
283 while (_i < _j)
284 {
285 _k = (_j+_i-1)/2;
286 _comp_result = _comp_macro(_array[_k], _search_key);
287 if (_comp_result == 0)
288 {
289 _result_index = _k;
290 return true;
291 }
292 else if (_comp_result < 0)
293 {
294 _i = _k+1;
295 }
296 else
297 {
298 _j = _k;
299 }
300 }
301 _result_index = _i;
302 return false;
303 }
304
305
306
307 //! Failsafe Iterative binary search,Template version
308 /*!
309 If the element is not found, it returns the nearest upper element position, may be the further position after the last element.
310 \param _array
311 \param _start_i the beginning of the array
312 \param _end_i the ending index of the array
313 \param _search_key Value to find
314 \param _result_index the index of the found element, or if not found then it will get the index of the closest bigger value
315 \return true if found, else false
316 */
317 template<class T>
gim_binary_search(const T * _array,GUINT _start_i,GUINT _end_i,const T & _search_key,GUINT & _result_index)318 bool gim_binary_search(
319 const T*_array,GUINT _start_i,
320 GUINT _end_i,const T & _search_key,
321 GUINT & _result_index)
322 {
323 GUINT _i = _start_i;
324 GUINT _j = _end_i+1;
325 GUINT _k;
326 while(_i < _j)
327 {
328 _k = (_j+_i-1)/2;
329 if(_array[_k]==_search_key)
330 {
331 _result_index = _k;
332 return true;
333 }
334 else if (_array[_k]<_search_key)
335 {
336 _i = _k+1;
337 }
338 else
339 {
340 _j = _k;
341 }
342 }
343 _result_index = _i;
344 return false;
345 }
346
347
348
349 ///heap sort from http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Sort/Heap/
350 template <typename T, typename COMP_CLASS>
gim_down_heap(T * pArr,GUINT k,GUINT n,COMP_CLASS CompareFunc)351 void gim_down_heap(T *pArr, GUINT k, GUINT n,COMP_CLASS CompareFunc)
352 {
353 /* PRE: a[k+1..N] is a heap */
354 /* POST: a[k..N] is a heap */
355
356 T temp = pArr[k - 1];
357 /* k has child(s) */
358 while (k <= n/2)
359 {
360 int child = 2*k;
361
362 if ((child < (int)n) && CompareFunc(pArr[child - 1] , pArr[child])<0)
363 {
364 child++;
365 }
366 /* pick larger child */
367 if (CompareFunc(temp , pArr[child - 1])<0)
368 {
369 /* move child up */
370 pArr[k - 1] = pArr[child - 1];
371 k = child;
372 }
373 else
374 {
375 break;
376 }
377 }
378 pArr[k - 1] = temp;
379 } /*downHeap*/
380
381
382 template <typename T, typename COMP_CLASS>
gim_heap_sort(T * pArr,GUINT element_count,COMP_CLASS CompareFunc)383 void gim_heap_sort(T *pArr, GUINT element_count, COMP_CLASS CompareFunc)
384 {
385 /* sort a[0..N-1], N.B. 0 to N-1 */
386 GUINT k;
387 GUINT n = element_count;
388 for (k = n/2; k > 0; k--)
389 {
390 gim_down_heap(pArr, k, n, CompareFunc);
391 }
392
393 /* a[1..N] is now a heap */
394 while ( n>=2 )
395 {
396 gim_swap_elements(pArr,0,n-1); /* largest of a[0..n-1] */
397 --n;
398 /* restore a[1..i-1] heap */
399 gim_down_heap(pArr, 1, n, CompareFunc);
400 }
401 }
402
403
404
405
406 #endif // GIM_RADIXSORT_H_INCLUDED
407