Simple Application Framework  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Saf/Algo/Sort/MergeSort.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_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