Simple Application Framework
1
|
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