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_MERGESORT_H 00029 #define SAF_ALGO_SORT_MERGESORT_H 00030 00031 #include "../../Type.h" 00032 #include "../Predicate.h" 00033 #include "../Range.h" 00034 #include "../../Math/Range.h" 00035 #include "InsertionSort.h" 00036 #include "../../Collection/Queue.h" 00037 00038 namespace Saf 00039 { 00041 namespace Internal 00042 { 00043 namespace AlgoSort 00044 { 00046 template <class BidIter, class Pred> 00047 void MergeRangesInPlace(BidIter begin, BidIter mid, BidIter end, 00048 Size len1, Size len2, Pred pred) 00049 { 00050 if (len1 > 0 && len2 > 0) 00051 { 00052 if (len1 == 1 && len2 == 1) 00053 { 00054 if (pred(*mid, *begin)) 00055 { 00056 Algo::Swap(*mid, *begin); 00057 } 00058 } 00059 else 00060 { 00061 Size lenLeft, lenRight; 00062 BidIter cutLeft = begin; 00063 BidIter cutRight = mid; 00064 00065 if (len1 > len2) 00066 { 00067 lenLeft = len1 / 2; 00068 Algo::Range::Advance(cutLeft, lenLeft); 00069 00070 cutRight = Math::Range::LowerBound(mid, end, *cutLeft, pred); 00071 lenRight = Algo::Range::Distance(mid, cutRight); 00072 } 00073 else 00074 { 00075 lenRight = len2 / 2; 00076 Algo::Range::Advance(cutRight, lenRight); 00077 00078 cutLeft = Math::Range::UpperBound(begin, mid, *cutRight, pred); 00079 lenLeft = Algo::Range::Distance(begin, cutLeft); 00080 } 00081 00082 BidIter newMid = cutLeft; 00083 Algo::Range::Advance(newMid, lenRight); 00084 00085 if (lenRight != 0) 00086 { 00087 Algo::Range::Rotate(cutLeft, mid, cutRight); 00088 MergeRangesInPlace(begin, cutLeft, newMid, lenLeft, lenRight, pred); 00089 } 00090 00091 MergeRangesInPlace(newMid, cutRight, end, len1 - lenLeft, len2 - lenRight, pred); 00092 } 00093 } 00094 } 00095 00097 template <class BidIter, class Pred> 00098 void MergeRanges(BidIter begin, BidIter mid, BidIter end, Size len1, Size len2, Pred pred) 00099 { 00100 Saf::Collection::Queue<typename Type::IteratorTraits<BidIter>::ValType> queue; 00101 00102 // Copy first half out 00103 for (BidIter cur = begin; cur != mid; ++cur) 00104 { 00105 queue.Push(*cur); 00106 } 00107 00108 // Merge 00109 while (begin != mid && mid != end) 00110 { 00111 if (pred(*mid, queue.Front())) 00112 { 00113 *begin = *mid; 00114 ++mid; 00115 } 00116 else 00117 { 00118 *begin = queue.Front(); 00119 queue.Pop(); 00120 } 00121 00122 ++begin; 00123 } 00124 00125 // Copy tail 00126 while (!queue.IsEmpty()) 00127 { 00128 *begin = queue.Front(); 00129 queue.Pop(); 00130 ++begin; 00131 } 00132 } 00133 } 00134 } 00137 namespace Algo 00138 { 00139 namespace Sort 00140 { 00156 template <class BidIter, class Pred> 00157 void MergeSortInPlace(BidIter begin, BidIter end, Pred pred) 00158 { 00159 Size len = Range::Distance(begin, end); 00160 00161 if (len > 24) 00162 { 00163 Size half = len / 2; 00164 00165 // Find middle element 00166 BidIter mid = begin; 00167 Range::Advance(mid, half); 00168 00169 // Recursion 00170 MergeSortInPlace(begin, mid, pred); 00171 MergeSortInPlace(mid, end, pred); 00172 00173 // Merging 00174 Internal::AlgoSort::MergeRangesInPlace(begin, mid, end, half, 00175 len - half, pred); 00176 } 00177 else 00178 { 00179 InsertionSort(begin, end, pred); 00180 } 00181 } 00182 00197 template <class BidIter> 00198 void MergeSortInPlace(BidIter begin, BidIter end) 00199 { 00200 Predicate::Less<typename Type::IteratorTraits<BidIter>::ValType> pred; 00201 MergeSortInPlace(begin, end, pred); 00202 } 00203 00206 template <class BidIter, class Pred> 00207 void MergeSort(BidIter begin, BidIter end, Pred pred) 00208 { 00209 Size len = Range::Distance(begin, end); 00210 00211 if (len > 24) 00212 { 00213 Size half = len / 2; 00214 00215 // Find middle element 00216 BidIter mid = begin; 00217 Range::Advance(mid, half); 00218 00219 // Recursion 00220 MergeSort(begin, mid, pred); 00221 MergeSort(mid, end, pred); 00222 00223 // Merging 00224 Internal::AlgoSort::MergeRanges(begin, mid, end, half, len - half, pred); 00225 } 00226 else 00227 { 00228 Sort::InsertionSort(begin, end, pred); 00229 } 00230 } 00231 } 00232 } 00233 } 00234 00235 #endif