"L. Spiro Engine"
|
00001 00016 #ifndef __LSTL_ALGORITHM_H__ 00017 #define __LSTL_ALGORITHM_H__ 00018 00019 #include "../LSTLib.h" 00020 #include "../Vector/LSTLSVectorPoD.h" 00021 #include "../Vector/LSTLVector.h" 00022 #include "../Vector/LSTLVectorPoD.h" 00023 00024 #pragma warning( push ) 00025 00026 // warning C4127: conditional expression is constant 00027 #pragma warning( disable : 4127 ) 00028 00029 namespace lstl { 00030 00036 class CAlgorithm { 00037 // All is public. This class has no secrets. 00038 public : 00039 00048 template <typename _tType, typename _tDataType, unsigned _uAllocSize> 00049 static LSUINT32 LSE_CALL Find( const CVectorPoD<_tType, _tDataType, _uAllocSize> &_vVec, const _tType &_tVal ) { 00050 for ( LSUINT32 I = 0UL; I < _vVec.Length(); ++I ) { 00051 if ( _vVec[I] == _tVal ) { return I; } 00052 } 00053 return _vVec.Length(); 00054 } 00055 00064 template <typename _tType, typename _tDataType, unsigned _uAllocSize> 00065 static LSUINT32 LSE_CALL Find( const CSVectorPoD<_tType, _tDataType, _uAllocSize> &_vVec, const _tType &_tVal ) { 00066 for ( LSUINT32 I = 0UL; I < _vVec.Length(); ++I ) { 00067 if ( _vVec[I] == _tVal ) { return I; } 00068 } 00069 return _vVec.Length(); 00070 } 00071 00080 template <typename _tType, typename _tDataType, unsigned _uAllocSize> 00081 static LSUINT32 LSE_CALL Find( const CVector<_tType, _tDataType, _uAllocSize> &_vVec, const _tType &_tVal ) { 00082 for ( LSUINT32 I = 0UL; I < _vVec.Length(); ++I ) { 00083 if ( _vVec[I] == _tVal ) { return I; } 00084 } 00085 return _vVec.Length(); 00086 } 00087 00098 template <typename _tType, typename _tDataType, unsigned _uAllocSize> 00099 static LSBOOL LSE_CALL BSearch( const CVector<_tType, _tDataType, _uAllocSize> &_vVec, const _tType &_tVal, LSUINT32 &_ui32Index ) { 00100 return BSearch<_tType, _tDataType, _uAllocSize, _tType>( _vVec, _tVal, _ui32Index ); 00101 } 00102 00113 template <typename _tType, typename _tDataType, unsigned _uAllocSize, typename _tKeyType> 00114 static LSBOOL LSE_CALL BSearch( const CVector<_tType, _tDataType, _uAllocSize> &_vVec, const _tKeyType &_tVal, LSUINT32 &_ui32Index ) { 00115 if ( !_vVec.Length() ) { 00116 _ui32Index = 0UL; 00117 return false; 00118 } 00119 00120 // Do a binary search for the key. 00121 LSUINT32 ui32Jmp = _vVec.Length() >> 1UL; 00122 LSUINT32 ui32IndexToCheck = static_cast<LSUINT32>(-static_cast<LSINT32>(ui32Jmp)); 00123 do { 00124 ui32IndexToCheck += ui32Jmp; 00125 if ( ui32IndexToCheck >= _vVec.Length() ) { 00126 // Passed the end of the list. Go back. 00127 ui32IndexToCheck -= ui32Jmp; 00128 ui32Jmp >>= 1UL; 00129 // No point in jumping beyond the end of the list. 00130 ui32Jmp = CStd::Min<LSUINT32>( ui32Jmp, _vVec.Length() - ui32IndexToCheck - 1UL ); 00131 continue; 00132 } 00133 // Check if we passed the item we want to find. 00134 if ( _vVec[ui32IndexToCheck] < _tVal ) { 00135 if ( ui32Jmp == 0UL ) { 00136 // The given key is greater than the current index. It should be inserted after. 00137 _ui32Index = ui32IndexToCheck + 1UL; 00138 return false; 00139 } 00140 continue; 00141 } 00142 if ( _vVec[ui32IndexToCheck] == _tVal ) { 00143 _ui32Index = ui32IndexToCheck; 00144 return true; 00145 } 00146 // If the jump is already 0, we can leave here with this being the final index. 00147 if ( ui32Jmp == 0UL || ui32IndexToCheck == 0UL ) { 00148 _ui32Index = ui32IndexToCheck; 00149 return false; 00150 } 00151 // Go back and jump by half as much. 00152 ui32IndexToCheck -= ui32Jmp; 00153 ui32Jmp >>= 1UL; 00154 // No point in jumping beyond the end of the list. 00155 ui32Jmp = CStd::Min<LSUINT32>( ui32Jmp, _vVec.Length() - ui32IndexToCheck - 1UL ); 00156 } while ( true ); 00157 } 00158 00167 template <typename _tType> 00168 static LSVOID LSE_CALL ShortSort( _tType * _ptValues, LSUINTPTR _uiptrTotal ) { 00169 _tType * ptLow = _ptValues; 00170 _tType * ptHi = _ptValues + _uiptrTotal; 00171 _tType * ptP, * ptMax; 00172 // Note: In assertions below, i and j are alway inside original bounds of the 00173 // array to sort. 00174 00175 while ( ptHi > ptLow ) { 00176 // A[i] <= A[j] for i <= j, j > hi 00177 ptMax = ptLow; 00178 for ( ptP = ptLow + 1; ptP <= ptHi; ++ptP ) { 00179 // A[i] <= A[ptMax] for lo <= i < p 00180 if ( (*ptMax) < (*ptP) ) { 00181 ptMax = ptP; 00182 } 00183 // A[i] <= A[ptMax] for lo <= i <= p 00184 } 00185 00186 // A[i] <= A[ptMax] for lo <= i <= hi 00187 _tType tTemp = (*ptMax); 00188 (*ptMax) = (*ptHi); 00189 (*ptHi) = tTemp; 00190 00191 // A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi 00192 --ptHi; 00193 00194 // A[i] <= A[j] for i <= j, j > hi, loop top condition established 00195 } 00196 // A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j, 00197 // so array is sorted. 00198 } 00199 00206 template <typename _tType> 00207 static LSVOID LSE_CALL QSort( _tType * _ptValues, LSUINTPTR _uiptrTotal ) { 00208 #define LSSTL_STACKSIZE (8UL * sizeof( LSVOID * ) - 2UL) 00209 00210 _tType * ptLow, * ptHigh; 00211 _tType * ptMid; 00212 _tType * ptLowGuy, * ptHighGuy; 00213 LSUINTPTR uiptrSize; 00214 _tType * ptLowStack[LSSTL_STACKSIZE], * ptHighStack[LSSTL_STACKSIZE]; 00215 LSINT32 i32StackPointer; 00216 #undef LSSTL_STACKSIZE 00217 00218 // Validate the parameters. 00219 if ( !(_ptValues != NULL || _uiptrTotal == 0UL) ) { return; } 00220 if ( _uiptrTotal < 2UL ) { return; } 00221 00222 // Initialize the stack. 00223 i32StackPointer = 0; 00224 00225 // Initialize the limits. 00226 ptLow = _ptValues; 00227 ptHigh = _ptValues + (_uiptrTotal - 1UL); 00228 00229 00230 Recurse : 00231 00232 // Number of elements to sort. 00233 uiptrSize = (ptHigh - ptLow) + 1; 00234 00235 // Below a certain size, it is faster to use an O(n^2) sorting method. 00236 if ( uiptrSize <= 8 ) { 00237 ShortSort( ptLow, uiptrSize - 1 ); 00238 } 00239 else { 00240 // First we pick a partitioning element. The efficiency of the 00241 // algorithm demands that we find one that is approximately the median 00242 // of the values, but also that we select one quickly. We choose the 00243 // median of the first, middle, and last elements, to avoid bad 00244 // performance in the face of already-sorted data, or data that is made 00245 // up of multiple sorted runs appended together. Testing shows that a 00246 // median-of-three algorithm provides better performance than simply 00247 // picking the middle element for the latter case. 00248 00249 // Find the middle element. 00250 ptMid = ptLow + (uiptrSize >> 1); 00251 00252 // Sort the first, middle, last elements into order. 00253 if ( (*ptMid) < (*ptLow) ) { 00254 ShortSwap( ptLow, ptMid ); 00255 } 00256 if ( (*ptHigh) < (*ptLow) ) { 00257 ShortSwap( ptLow, ptHigh ); 00258 } 00259 if ( (*ptHigh) < (*ptMid) ) { 00260 ShortSwap( ptMid, ptHigh ); 00261 } 00262 00263 // We now wish to partition the array into three pieces, one consisting 00264 // of elements <= partition element, one of elements equal to the 00265 // partition element, and one of elements > than it. This is done 00266 // below; comments indicate conditions established at every step. 00267 00268 ptLowGuy = ptLow; 00269 ptHighGuy = ptHigh; 00270 00271 // Note that ptHighGuy decreases and ptLowGuy increases on every iteration, 00272 // so loop must terminate. 00273 for ( ; ; ) { 00274 // ptLow <= ptLowGuy < ptHigh, ptLow < ptHighGuy <= ptHigh, 00275 // A[i] <= A[ptMid] for ptLow <= i <= ptLowGuy, 00276 // A[i] > A[ptMid] for ptHighGuy <= i < ptHigh, 00277 // A[ptHigh] >= A[ptMid] 00278 00279 // The doubled loop is to avoid calling _psfFunc( ptMid, ptMid ), since some 00280 // existing comparison functions don't work when passed the same 00281 // value for both pointers. 00282 if ( ptMid > ptLowGuy ) { 00283 do { 00284 ++ptLowGuy; 00285 } while ( ptLowGuy < ptMid && ((*ptLowGuy) < (*ptMid) || 00286 (*ptLowGuy) == (*ptMid)) ); 00287 } 00288 if ( ptMid <= ptLowGuy ) { 00289 do { 00290 ++ptLowGuy; 00291 } while ( ptLowGuy <= ptHigh && ((*ptLowGuy) < (*ptMid) || 00292 (*ptLowGuy) == (*ptMid)) ); 00293 } 00294 00295 // ptLow < ptLowGuy <= ptHigh+1, A[i] <= A[ptMid] for ptLow <= i < ptLowGuy, 00296 // either ptLowGuy > ptHigh or A[ptLowGuy] > A[ptMid] 00297 00298 do { 00299 --ptHighGuy; 00300 } while ( ptHighGuy > ptMid && 00301 (*ptMid) < (*ptHighGuy) ); 00302 00303 // ptLow <= ptHighGuy < ptHigh, A[i] > A[ptMid] for ptHighGuy < i < ptHigh, 00304 // either ptHighGuy == ptLow or A[ptHighGuy] <= A[ptMid] 00305 00306 if ( ptHighGuy < ptLowGuy ) { 00307 break; 00308 } 00309 00310 // if ptLowGuy > ptHigh or ptHighGuy == ptLow, then we would have exited, so 00311 // A[ptLowGuy] > A[ptMid], A[ptHighGuy] <= A[ptMid], 00312 // ptLowGuy <= ptHigh, ptHighGuy > ptLow 00313 00314 ShortSwap( ptLowGuy, ptHighGuy ); 00315 00316 // If the partition element was moved, follow it. Only need 00317 // to check for ptMid == ptHighGuy, since before the swap, 00318 // A[ptLowGuy] > A[ptMid] implies ptLowGuy != ptMid. 00319 00320 if ( ptMid == ptHighGuy ) { 00321 ptMid = ptLowGuy; 00322 } 00323 00324 // A[ptLowGuy] <= A[ptMid], A[ptHighGuy] > A[ptMid]; so condition at top 00325 // of loop is re-established. 00326 } 00327 00328 // A[i] <= A[ptMid] for ptLow <= i < ptLowGuy, 00329 // A[i] > A[ptMid] for ptHighGuy < i < ptHigh, 00330 // A[ptHigh] >= A[ptMid] 00331 // ptHighGuy < ptLowGuy 00332 // implying: 00333 // ptHighGuy == ptLowGuy-1 00334 // or ptHighGuy == ptHigh - 1, ptLowGuy == ptHigh + 1, A[ptHigh] == A[ptMid] 00335 00336 // Find adjacent elements equal to the partition element. The 00337 // doubled loop is to avoid calling _psfFunc( ptMid, ptMid ), since some 00338 // existing comparison functions don't work when passed the same value 00339 // for both pointers. 00340 00341 ++ptHighGuy; 00342 if ( ptMid < ptHighGuy ) { 00343 do { 00344 --ptHighGuy; 00345 } while ( ptHighGuy > ptMid && 00346 (*ptHighGuy) == (*ptMid) ); 00347 } 00348 if ( ptMid >= ptHighGuy ) { 00349 do { 00350 --ptHighGuy; 00351 } while ( ptHighGuy > ptLow && 00352 (*ptHighGuy) == (*ptMid) ); 00353 } 00354 00355 // Okay, now we have the following: 00356 // ptHighGuy < ptLowGuy 00357 // ptLow <= ptHighGuy <= ptHigh 00358 // A[i] <= A[ptMid] for ptLow <= i <= ptHighGuy 00359 // A[i] == A[ptMid] for ptHighGuy < i < ptLowGuy 00360 // A[i] > A[ptMid] for ptLowGuy <= i < ptHigh 00361 // A[ptHigh] >= A[ptMid] 00362 00363 // We've finished the partition; now we want to sort the subarrays 00364 // [ptLow, ptHighGuy] and [ptLowGuy, ptHigh]. 00365 // We do the smaller one first to minimize stack usage. 00366 // We only sort arrays of length 2 or more. 00367 00368 if ( ptHighGuy - ptLow >= ptHigh - ptLowGuy ) { 00369 if ( ptLow < ptHighGuy ) { 00370 ptLowStack[i32StackPointer] = ptLow; 00371 ptHighStack[i32StackPointer] = ptHighGuy; 00372 ++i32StackPointer; 00373 } 00374 00375 if ( ptLowGuy < ptHigh ) { 00376 ptLow = ptLowGuy; 00377 goto Recurse; 00378 } 00379 } 00380 else { 00381 if ( ptLowGuy < ptHigh ) { 00382 ptLowStack[i32StackPointer] = ptLowGuy; 00383 ptHighStack[i32StackPointer] = ptHigh; 00384 ++i32StackPointer; 00385 } 00386 00387 if ( ptLow < ptHighGuy ) { 00388 ptHigh = ptHighGuy; 00389 goto Recurse; 00390 } 00391 } 00392 } 00393 00394 // We have sorted the array except for any pending sorts on the stack. 00395 // Check if there are any and do them. 00396 --i32StackPointer; 00397 if ( i32StackPointer >= 0 ) { 00398 ptLow = ptLowStack[i32StackPointer]; 00399 ptHigh = ptHighStack[i32StackPointer]; 00400 00401 // Pop array from the stack. 00402 goto Recurse; 00403 } 00404 else { return; } 00405 } 00406 00407 00408 protected : 00409 // == Functions. 00416 template <typename _tType> 00417 static LSVOID LSE_CALL ShortSwap( _tType * _ptA, 00418 _tType * _ptB ) { 00419 _tType tTemp = (*_ptA); 00420 (*_ptA) = (*_ptB); 00421 (*_ptB) = tTemp; 00422 } 00423 00424 }; 00425 00426 00427 } // namespace lstl 00428 00429 #pragma warning( pop ) 00430 00431 #endif // __LSTL_ALGORITHM_H__