> module Sort                   (  qsort, qsortBy,
>                                  mergeSort, mergeSortBy,
>                                  merge, mergeLists, mergeBy, mergeListsBy,
>                                  naturalSort, naturalSortBy,
>                                  uniqueBy, unique
>                               )
> where


Quicksort


> qsort                         :: Ord a => [a] -> [a]
> qsort                         =  qsortBy (<=)
>
> qsortBy                       :: (a -> a -> Bool) -> [a] -> [a]
> qsortBy (<=) x                =  qsortsBy (<=) x []


The following code is due to Lennart Augustsson.


> qsortsBy                      :: (a -> a -> Bool) -> [a] -> [a] -> [a]
> qsortsBy (<=) []    y         =  y
> qsortsBy (<=) [a]   y         =  a:y
> qsortsBy (<=) (a:x) y         =  qpartBy (<=) a x [] [] y


qpartBy partitions and sorts the sublists. Note that l and r are in reverse order and must be sorted with an anti-stable sorting.


> qpartBy (<=) a [] l r y       =  rqsortsBy (<=) l (a : rqsortsBy (<=) r y)
> qpartBy (<=) a (b:x) l r y
>     | a <= b                  =  qpartBy (<=) a x l (b:r) y
>     | otherwise               =  qpartBy (<=) a x (b:l) r y


rqsortsBy is as qsortsBy but anti-stable, ie reverses equal elements.


> rqsortsBy                     :: (a -> a -> Bool) -> [a] -> [a] -> [a]
> rqsortsBy (<=) []    y        =  y
> rqsortsBy (<=) [a]   y        =  a:y
> rqsortsBy (<=) (a:x) y        =  rqpartBy (<=) a x [] [] y



> rqpartBy (<=) a [] l r y      =  qsortsBy (<=) l (a : qsortsBy (<=) r y)
> rqpartBy (<=) a (b:x) l r y
>     | b <= a                  =  rqpartBy (<=) a x (b:l) r y
>     | otherwise               =  rqpartBy (<=) a x l (b:r) y


Mergesort

Bottom-up Variant of mergesort.


> mergeSort                     :: Ord a => [a] -> [a]
> mergeSort                     =  mergeSortBy (<=)



> mergeSortBy                   :: (a -> a -> Bool) -> [a] -> [a]
> mergeSortBy (<=)              =  mergeListsBy (<=) . runPhase
>     where


Building "runs" of length 2.


>     runPhase []               =  []
>     runPhase [a]              =  [[a]]
>     runPhase (a:b:x)
>         | a <= b              =  [a,b] : runPhase x
>         | otherwise           =  [b,a] : runPhase x


Merging two lists.


> merge                         :: Ord a => [a] -> [a] -> [a]
> merge                         =  mergeBy (<=)
>
> mergeBy                       :: (a -> a -> Bool) -> [a] -> [a] -> [a]
> mergeBy (<=) [] y             =  y
> mergeBy (<=) (a:x) []         =  a : x
> mergeBy (<=) v@(a:x) w@(b:y)
>     | a <= b                  =  a : mergeBy (<=) x w
>     | otherwise               =  b : mergeBy (<=) v y


Iteratively merging the runs. Good for its own sake.


> mergeLists                    :: Ord a => [[a]] -> [a]
> mergeLists                    =  mergeListsBy (<=)
>
> mergeListsBy                  :: (a -> a -> Bool) -> [[a]] -> [a]
> mergeListsBy (<=)             =  mergeLists
>     where
>     mergeLists []             =  []
>     mergeLists [x]            =  x
>     mergeLists (x1:x2:xs)     =  mergeLists (mergeBy (<=) x1 x2:mergePairs xs)
>
>     mergePairs []             =  []
>     mergePairs [x]            =  [x]
>     mergePairs (x1:x2:xs)     =  mergeBy (<=) x1 x2 : mergePairs xs


Natural mergesort

Natural mergesort respect runs of the given list.


> naturalSort                   :: Ord a => [a] -> [a]
> naturalSort                   =  naturalSortBy (<=)



> naturalSortBy                 :: (a -> a -> Bool) -> [a] -> [a]
> naturalSortBy (<=)            =  mergeListsBy (<=) . runPhase
>     where


Splitting into runs. takeAsc takes an ascending prefix.


>     runPhase []               =  [[]]
>     runPhase (a:x)            =  takeAsc [a] x
>
>     takeAsc as []             =  [reverse as]
>     takeAsc as@(a:_) (e:x)
>         | a <= e              =  takeAsc (e:as) x
>         | otherwise           =  takeAscDes as [e] x
>
>     takeAscDes as ds []       =  [mergeBy (<=) (reverse as) ds]
>     takeAscDes as@(a:_) ds@(d:_) v@(e:x)
>         | a <= e              =  takeAscDes (e:as) ds x
>         | d <= e              =  mergeBy (<=) (reverse as) ds : runPhase v
>         | otherwise           =  takeAscDes as (e:ds) x


ToDo: Is naturalSortBy stable?

Misc


> uniqueBy                              :: (a -> a -> Bool) -> [a] -> [a]
> uniqueBy (==) []                      =  []
> uniqueBy (==) [a]                     =  [a]
> uniqueBy (==) (a:x@(b:_)) | a==b      =  uniqueBy (==) x
>                           | otherwise =  a : uniqueBy (==) x



> unique                                :: Eq a => [a] -> [a]
> unique                                =  uniqueBy (==)