Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you do an in-place quicksort in Haskell

Tags:

haskell

Could somebody provide an in-place quicksort haskell function? I.e. it returns a new sorted list, but the input list is copied to a mutable array or something.

I want to see how to do this, because I have a performance critical program where i need to simulate races and tally scores. If I use immutable data structures for this, each race will take O(log(numRaces) + numRunners) time, whereas if I use mutable arrays etc, each race will take O(log(numRaces)) time.

oh by the way i didn't actually need to do quicksort, i just wanted an example to see how to use mutable arrays effectively

like image 452
Nicholas Grasevski Avatar asked Mar 11 '11 01:03

Nicholas Grasevski


People also ask

Can quicksort be done in place?

The sub-arrays are then sorted recursively. This can be done in-place, requiring small additional amounts of memory to perform the sorting. Quicksort is a comparison sort, meaning that it can sort items of any type for which a "less-than" relation (formally, a total order) is defined.

How does quicksort work in Haskell?

The quicksort function uses the “divide and conquer” technique for sorting: We choose a pivot element from the list and divide the list into two halves, such that elements less than and equal to the pivot are placed on the left side, and elements greater than the pivot are placed on the right.

How do you quicksort step by step?

As a result, the quick sort method can be summarized in three steps: Pick: Select an element. Divide: Split the problem set, move smaller parts to the left of the pivot and larger items to the right. Repeat and combine: Repeat the steps and combine the arrays that have previously been sorted.


3 Answers

Here's a version, just to prove you can convert code from Wikipedia almost exactly into 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
like image 147
porges Avatar answered Jan 05 '23 05:01

porges


See 'sort' in the vector-algorithms package: http://hackage.haskell.org/packages/archive/vector-algorithms/0.4/doc/html/src/Data-Vector-Algorithms-Intro.html#sort

like image 45
Don Stewart Avatar answered Jan 05 '23 07:01

Don Stewart


Check out this code, it has a quick sort version that uses arrays from IO module. You can adapt it to your needs. Keep in mind though that imperative programming in Haskell can give you headaches if you are not careful (mine programs usually suffered from huge memory use and 90% time spent in garbage collection).

like image 30
Marek Sapota Avatar answered Jan 05 '23 07:01

Marek Sapota