Simple Application Framework  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Saf/Algo/Sort/SortInternal.h
Go to the documentation of this file.
00001 /*
00002     This file is part of Simple Application Framework (Saf) library.
00003     Copyright (C) 2010 - 2012 Ondrej Danek <ondrej.danek@gmail.com>
00004 
00005     This library is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published 
00007     by the Free Software Foundation, either version 3 of the License, or
00008     (at your option) any later version.
00009 
00010     Saf is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Simple Application Framework library. If not, 
00017     see <http://www.gnu.org/licenses/>.
00018 */
00019 
00028 #ifndef SAF_ALGO_SORT_SORTINTERNAL_H
00029 #define SAF_ALGO_SORT_SORTINTERNAL_H
00030 
00031 #include "../../Type.h"
00032 #include "../Swap.h"
00033 #include "../Predicate.h"
00034 #include "../Selection/Median.h"
00035 #include "../../Collection/Pair.h"
00036 
00037 namespace Saf
00038 {
00040     namespace Internal
00041     {
00042         namespace AlgoSort
00043         {
00048             template <class Iter, class Pred>
00049             class PredicateOverIterators
00050             {
00051             private:
00052                 Pred m_pred;
00053 
00054             public:
00055                 PredicateOverIterators(const Pred &p)
00056                     : m_pred(p)
00057                 {}
00058 
00059                 bool operator()(const Iter& x, const Iter& y) const
00060                 {
00061                     return m_pred(*x, *y);
00062                 }
00063             };
00064 
00066             template <class RanIter, class Pred>
00067             inline RanIter ChoosePivot(RanIter first, RanIter last, Pred pred)
00068             {
00069                 // Modified predicate that works on iterators
00070                 PredicateOverIterators<RanIter,Pred> pa(pred);
00071         
00072                 // Median-of-3
00073                 RanIter mid = first + (last - first) / 2;
00074                 return Saf::Algo::Selection::Median(first, mid, last, pa);
00075             }
00076 
00083             template <class RanIter, class Pred>
00084             Saf::Collection::Pair<RanIter,RanIter> PartitionGeneric(RanIter begin, RanIter end, Pred pred)
00085             {
00086                 --end;
00087                 RanIter pivot = ChoosePivot(begin, end, pred);
00088 
00089                 // Store pivot at the end of the sequence
00090                 if (pivot != end)
00091                 {
00092                     Saf::Algo::Swap(*pivot, *end);
00093                     pivot = end;
00094                 }            
00095 
00096                 // Reorder the rest of the sequence
00097                 while (begin != end)
00098                 {
00099                     if (pred(*begin, *pivot))
00100                     {
00101                         ++begin;
00102                     }
00103                     else
00104                     {
00105                         --end;
00106                         Saf::Algo::Swap(*begin, *end);
00107                     }
00108                 }
00109 
00110                 // Put pivot between the two partitions and return ranges
00111                 if (begin == pivot)
00112                 {
00113                     return Saf::Collection::Pair<RanIter,RanIter>(begin, begin);
00114                 }
00115 
00116                 Saf::Algo::Swap(*begin, *pivot);
00117                 return Saf::Collection::Pair<RanIter,RanIter>(begin, begin + 1);
00118             }
00119 
00129             template <class RanIter, class Pred>
00130             Saf::Collection::Pair<RanIter,RanIter> PartitionSmart(RanIter begin, RanIter end, Pred pred)
00131             {        
00132                 // Choose pivot and put it to the middle
00133                 RanIter pivot = ChoosePivot(begin, end - 1, pred);            
00134                 RanIter mid = begin + (end - begin) / 2;
00135                 Saf::Algo::Swap(*mid, *pivot);
00136 
00137                 // Partitioning
00138                 RanIter mFirst, mLast;
00139             
00140                 for (mFirst = mid; mFirst != begin; --mFirst)
00141                 {
00142                     if (pred(*(mFirst - 1), *mid) || pred(*mid, *(mFirst - 1)))
00143                     {
00144                         break;
00145                     }
00146                 }
00147 
00148                 for (mLast = mid + 1; mLast != end; ++mLast)
00149                 {
00150                     if (pred(*mLast, *mid) || pred(*mid, *mLast))
00151                     {
00152                         break;
00153                     }
00154                 }
00155 
00156                 RanIter cLeft = mFirst;
00157                 RanIter cRight = mLast;
00158 
00159                 while (true)
00160                 {
00161                     while (cRight != end && !pred(*cRight, *mFirst))
00162                     {
00163                         if (!pred(*mFirst, *cRight))
00164                         {
00165                             Saf::Algo::Swap(*mLast, *cRight);
00166                             ++mLast;
00167                         } 
00168                     
00169                         ++cRight;
00170                     }
00171 
00172                     while (cLeft != begin && !pred(*mFirst, *(cLeft - 1)))
00173                     {
00174                         --cLeft;
00175 
00176                         if (!pred(*cLeft, *mFirst))
00177                         {
00178                             --mFirst;
00179                             Saf::Algo::Swap(*mFirst, *cLeft);
00180                         }                     
00181                     }
00182 
00183                     if (cLeft == begin && cRight == end)
00184                     {
00185                         return Saf::Collection::Pair<RanIter,RanIter>(mFirst, mLast);
00186                     }
00187 
00188                     if (cLeft == begin)
00189                     {
00190                         if (mLast != cRight)
00191                         {
00192                             Saf::Algo::Swap(*mFirst, *mLast);
00193                         }                    
00194                         Saf::Algo::Swap(*mFirst, *cRight);
00195 
00196                         ++mFirst;
00197                         ++mLast;
00198                         ++cRight;
00199                     }
00200                     else if (cRight == end)
00201                     {
00202                         --cLeft;
00203                         --mFirst;
00204                         --mLast;
00205 
00206                         if (cLeft != mFirst)
00207                         {
00208                             Saf::Algo::Swap(*cLeft, *mFirst);
00209                         }
00210                         Saf::Algo::Swap(*mFirst, *mLast);
00211                     }
00212                     else
00213                     {
00214                         --cLeft;
00215                         Saf::Algo::Swap(*cLeft, *cRight);
00216                         ++cRight;
00217                     }
00218                 }
00219             }
00220         }
00221     }
00223 }
00224 
00225 #endif