你如何在Haskell进行就地快速排序

时间:2011-03-11 01:59:21

标签: haskell

有人可以提供就地快速排序haskell功能吗?即它返回一个新的排序列表,但输入列表被复制到一个可变数组或其他东西。

我想看看如何做到这一点,因为我有一个性能关键程序,我需要模拟比赛和计数得分。如果我为此使用不可变数据结构,每个种族将采用O(log(numRaces)+ numRunners)时间,而如果我使用可变数组等,每个种族将采用O(log(numRaces))时间。

哦顺便说一下我实际上并不需要做快速排序,我只是想看一个例子来看看如何有效地使用可变数组

4 个答案:

答案 0 :(得分:28)

这是一个版本,只是为了证明你可以将维基百科中的代码几乎完全转换为Haskell;)

import Control.Monad.ST
import Data.Array.ST
import Data.Foldable
import Control.Monad

-- wiki-copied code starts here
partition arr left right pivotIndex = do
    pivotValue <- readArray arr pivotIndex
    swap arr pivotIndex right
    storeIndex <- foreachWith [left..right-1] left (\i storeIndex -> do
        val <- readArray arr i
        if (val <= pivotValue)
            then do
                 swap arr i storeIndex
                 return (storeIndex + 1)
            else do
                 return storeIndex )
    swap arr storeIndex right
    return storeIndex

qsort arr left right = when (right > left) $ do
    let pivotIndex = left + ((right-left) `div` 2)
    newPivot <- partition arr left right pivotIndex

    qsort arr left (newPivot - 1)
    qsort arr (newPivot + 1) right

-- wrapper to sort a list as an array
sortList xs = runST $ do
    let lastIndex = length xs - 1
    arr <- newListArray (0,lastIndex) xs :: ST s (STUArray s Int Int)
    qsort arr 0 lastIndex
    newXs <- getElems arr
    return newXs

-- test example
main = print $ sortList [212498,127,5981,2749812,74879,126,4,51,2412]

-- helpers
swap arr left right = do
    leftVal <- readArray arr left
    rightVal <- readArray arr right
    writeArray arr left rightVal
    writeArray arr right leftVal

-- foreachWith takes a list, and a value that can be modified by the function, and
-- it returns the modified value after mapping the function over the list.  
foreachWith xs v f = foldlM (flip f) v xs

答案 1 :(得分:6)

答案 2 :(得分:2)

签出this代码,它有一个快速排序版本,使用IO模块中的数组。您可以根据自己的需求进行调整。请记住,如果你不小心,Haskell中的命令式编程会给你带来麻烦(我的程序通常遭受巨大的内存使用和90%的垃圾收集时间)。

答案 3 :(得分:-2)

语法上我最喜欢这个:

main :: IO ()
main = do print $ qs "qwertzuiopasdfghjklyxcvbnm"

qs :: Ord a => [a] -> [a]
qs []     = []
qs (x:xs) = qs lt ++ [x] ++ qs gt
                    where
                        lt = [y | y <- xs, y <= x] 
                        gt = [y | y <- xs, y > x]