"L. Spiro Engine"

F:/My Projects/LSEngine/Modules/LSTL/Src/Algorithm/LSTLAlgorithm.h

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__
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator