Как вы выполняете быструю сортировку на месте в Haskell

Может ли кто-нибудь предоставить функцию quicksort-haskell на месте? То есть он возвращает новый отсортированный список, но список ввода копируется в изменяемый массив или что-то в этом роде.

Я хочу посмотреть, как это сделать, потому что у меня есть критически важная для производительности программа, в которой мне нужно моделировать расы и подсчет очков. Если я использую для этого неизменяемые структуры данных, каждая гонка будет принимать время O (log (numRaces) + numRunners), тогда как если я буду использовать изменяемые массивы и т.д., Каждая гонка будет принимать время O (log (numRaces)).

oh, кстати, мне не нужно было делать quicksort, мне просто нужен пример, чтобы эффективно использовать изменяемые массивы.

Ответы

Ответ 1

Вот версия, просто чтобы доказать, что вы можете конвертировать код из Википедии почти точно в 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

Ответ 3

Отметьте этот код, он имеет быструю сортировку, в которой используются массивы из модуля ввода-вывода. Вы можете адаптировать его к вашим потребностям. Имейте в виду, что это обязательное программирование в Haskell может дать вам головные боли, если вы не будете осторожны (мои программы обычно страдают от огромного использования памяти и 90% времени, затраченного на сбор мусора).

Ответ 4

синтаксически мне нравится это лучше всего:

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]