Simple Application Framework  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Saf/Algo/Sort/IntroSort.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_INTROSORT_H
00029 #define SAF_ALGO_SORT_INTROSORT_H
00030 
00031 #include "../../Type.h"
00032 #include "../Predicate.h"
00033 #include "../../Math/Calculus/Powers.h"
00034 #include "../../Collection/Pair.h"
00035 #include "HeapSort.h"
00036 #include "InsertionSort.h"
00037 #include "SortInternal.h"
00038 
00039 namespace Saf
00040 {
00042     namespace Internal
00043     {
00044         namespace AlgoSort
00045         {
00047             const Saf::Diff IntroSortInsertionLimit = 32;
00048 
00050             template <class RanIter, class Pred>
00051             void IntroSort(RanIter begin, RanIter end, Pred pred, Saf::Size depthLimit)
00052             {
00053                 while (Saf::Diff(end - begin) > IntroSortInsertionLimit && depthLimit > 0)
00054                 {
00055                     --depthLimit;
00056 
00057                     // Find pivot and partition the sequence into two parts
00058                     Saf::Collection::Pair<RanIter,RanIter> cut;
00059                     cut = Internal::AlgoSort::PartitionSmart(begin, end, pred);
00060 
00061                     // No need to proceed with the shorter sequence due to the
00062                     // logarithmic recursion bound given by depthLimit.
00063                     IntroSort(cut.m_second, end, pred, depthLimit);
00064                     end = cut.m_first;
00065                 }
00066 
00067                 if (Saf::Diff(end - begin) > IntroSortInsertionLimit)
00068                 {
00069                     // Too many recursions, use heap sort to sort the rest
00070                     Saf::Algo::Sort::HeapSort(begin, end, pred);
00071                 }
00072                 else
00073                 {
00074                     // Short sequence, use cache friendly insertion sort
00075                     Saf::Algo::Sort::InsertionSort(begin, end, pred);
00076                 }
00077             }
00078         }
00079     }
00082     namespace Algo
00083     {        
00084         namespace Sort
00085         {
00105             template <class RanIter, class Pred>
00106             void IntroSort(RanIter begin, RanIter end, Pred pred)
00107             {
00108                 Diff len = end - begin;
00109 
00110                 if (len > 1)
00111                 {
00112                     // Set the depth limit to 1.5 * log2(n)
00113                     Size depthLimit = 3 * Math::Calculus::BinaryLogarithm(Size(len)) / 2;
00114 
00115                     // Quicksort + insertion sort with a heap sort fallback
00116                     Internal::AlgoSort::IntroSort(begin, end, pred, depthLimit);
00117                 }                
00118             }
00119 
00138             template <class RanIter>
00139             void IntroSort(RanIter begin, RanIter end)
00140             {
00141                 Predicate::Less<typename Type::IteratorTraits<RanIter>::ValType> pred;
00142                 IntroSort(begin, end, pred);
00143             }
00144         }
00145     }
00146 }
00147 
00148 #endif