I am starting to learn Haskell and I've been reading this page on Haskell's wiki, which reports this qsort implementation:
qsort :: (Ord a) => [a] -> [a]
qsort [] = []
qsort (x:xs) = qsort less ++ [x] ++ qsort more
where less = filter (<x) xs
more = filter (>=x) xs
followed by a warning that this is not the most efficient way to do it, and linking an article which shows an incredibly verbose version of the same algorithm. Just by looking at it, I though that that was not what I was learning Haskell for, and I wanted to make a better version of the initial qsort without sacrificing its elegance. I mostly concentrated on eliminating the need to run filter
twice every call, and this is what I've come up:
filter' :: (a -> Bool) -> [a] -> ([a], [a])
filter' _ [] = ([], [])
filter' f a = filterInternal a ([], [])
where
filterInternal [] p = p
filterInternal (x:xs) (l, t)
| f x = filterInternal xs (x:l, t)
| otherwise = filterInternal xs (l, x:t)
qsort' :: (Ord a) => [a] -> [a]
qsort' [] = []
qsort' (x:xs) = qsort' less ++ [x] ++ qsort' more
where
(more, less) = filter' (>x) xs
But I am not sure this is really better. I mean, it works, but how does it compare to the initial version?
答案 0 :(得分:0)
这是我在思考大致相同问题时提出的解决方案(请指出任何警告!)。我没有想太多关于空间复杂性(尽管不应该太糟糕),只是时间。真正杀死天真qsort
的是O(n)
操作(++)
。因此,让我们使用一个新的数据结构(可折叠),以便我们快速连接。
{-# LANGUAGE DeriveFoldable #-}
import Data.Foldable
import Data.List
data Seq a = (Seq a) :++: (Seq a) | Leaf a | Empty deriving (Foldable)
然后,返回qsort'
的修改后的Seq a
将是
qsort' :: Ord a => [a] -> Seq a
qsort' [] = Empty
qsort' (x:xs) = qsort less :++: Leaf x :++: qsort more
where (less, more) = partition (<x) xs
而qsort
本身只是qsort = toList . qsort'
。
注意:涉及partition
的修补程序可以更好地为您提供常数因素,但++
vs :++:
表示qsort
现在可以优于O(n^2)
。此外,大多数排序实现都比这更好。这一点只是为了尽可能地反映“天真”的实施。